Repository: duckdb/duckdb
File: src/storage/storage_manager.cpp (C++)

Code before:
	}
	// write to the main WAL that we have initiated a checkpoint
	wal->WriteCheckpoint(meta_block);
	wal->Flush();

	// close the main WAL
	wal.reset();

	// replace the WAL with a new WAL (.checkpoint.wal) that transactions can write to while the checkpoint is happening
	// we don't eagerly write to this WAL - we just instantiate it here so it can be written to
	// if a checkpoint WAL already exists - delete it before proceeding
	auto checkpoint_wal_path = GetCheckpointWALPath();
	auto &fs = FileSystem::Get(db);
	fs.TryRemoveFile(checkpoint_wal_path);

	// the checkpoint WAL belongs to the NEXT checkpoint - when we are done we will overwrite the current WAL with it
	// as such override the checkpoint iteration number to the next one
	auto &single_file_block_manager = GetBlockManager().Cast<SingleFileBlockManager>();
	auto next_checkpoint_iteration = single_file_block_manager.GetCheckpointIteration() + 1;
	wal = make_uniq<WriteAheadLog>(*this, checkpoint_wal_path, 0ULL, WALInitState::NO_WAL, next_checkpoint_iteration);
	return true;
}

void StorageManager::WALFinishCheckpoint(lock_guard<mutex> &) {
	D_ASSERT(wal.get());
	ResetWAL();

	// "wal" points to the checkpoint WAL
	// first check if the checkpoint WAL has been written to
	auto &fs = FileSystem::Get(db);
	if (!wal->Initialized()) {
		// the checkpoint WAL has not been written to
		// this is the common scenario if there are no concurrent writes happening while checkpointing
		// in this case we can just remove the main WAL and re-instantiate it to empty
		fs.TryRemoveFile(wal_path);
		wal = make_uniq<WriteAheadLog>(*this, wal_path);
		return;
	}

	// we have had writes to the checkpoint WAL - we need to override our WAL with the checkpoint WAL
	// first close the WAL writer
	auto checkpoint_wal_path = wal->GetPath();
	wal.reset();

	// move the secondary WAL over the main WAL
	fs.MoveFile(checkpoint_wal_path, wal_path);

	// open what is now the main WAL again
	wal = make_uniq<WriteAheadLog>(*this, wal_path);
	wal->Initialize();


Review comment (suggestion):
I don't think we should call `ResetWAL()` here, since the constructor of `WriteAheadLog` in the `!wal->Initialized()` branch already calls `ResetWAL()`, which then causes it to be called twice.

Actually, in `write_ahead_log.hpp` you wrote:
```C++
	//! Marks all blocks as modified. Should only be called prior to destructing the WAL.
	void MarkBlocksAsModified();
```
Maybe we can just call this function in `~WriteAheadLog` then? Instead of calling it in `ResetWAL`?

Or just be careful with calling this before each `~WriteAheadLog`, or add verification code in `~WriteAheadLog` that verifies that all blocks are marked as modified.

Code after:
	wal->Flush();

	// We no longer need to hold on to the WAL blocks here. If the checkpoint fails, we throw a fatal exception and
	// enter an inconsistent state. If it succeeds, then this WAL is no longer relevant.
	wal->MarkBlocksInUseAsModified();
	// close the main WAL
	wal.reset();

	// replace the WAL with a new WAL (.checkpoint.wal) that transactions can write to while the checkpoint is happening
	// we don't eagerly write to this WAL - we just instantiate it here so it can be written to
	// if a checkpoint WAL already exists - delete it before proceeding
	auto checkpoint_wal_path = GetCheckpointWALPath();
	auto &fs = FileSystem::Get(db);
	fs.TryRemoveFile(checkpoint_wal_path);

	// the checkpoint WAL belongs to the NEXT checkpoint - when we are done we will overwrite the current WAL with it
	// as such override the checkpoint iteration number to the next one
	auto &single_file_block_manager = GetBlockManager().Cast<SingleFileBlockManager>();
	auto next_checkpoint_iteration = single_file_block_manager.GetCheckpointIteration() + 1;
	wal = make_uniq<WriteAheadLog>(*this, checkpoint_wal_path, 0ULL, WALInitState::NO_WAL, next_checkpoint_iteration);
	return true;
}

void StorageManager::WALFinishCheckpoint(lock_guard<mutex> &) {
	D_ASSERT(wal.get());

	// "wal" points to the checkpoint WAL
	// first check if the checkpoint WAL has been written to
	auto &fs = FileSystem::Get(db);
	if (!wal->Initialized()) {
		// the checkpoint WAL has not been written to
		// this is the common scenario if there are no concurrent writes happening while checkpointing
		// in this case we can just remove the main WAL and re-instantiate it to empty
		fs.TryRemoveFile(wal_path);
		ResetWALEntriesCount();
		wal = make_uniq<WriteAheadLog>(*this, wal_path);
		return;
	}

	// we have had writes to the checkpoint WAL - we need to override our WAL with the checkpoint WAL
	// first close the WAL writer
	auto checkpoint_wal_path = wal->GetPath();
	wal.reset();

	// move the secondary WAL over the main WAL
	fs.MoveFile(checkpoint_wal_path, wal_path);

	// open what is now the main WAL again
	wal = make_uniq<WriteAheadLog>(*this, wal_path);
	wal->Initialize();