#pragma once
#include <atomic>
#include <functional>
#include <memory>
#include <string_view>
#include <vector>
#include "common/types/types.h"
#include "storage//file_handle.h"
#include "storage/index/hash_index_utils.h"
#include "storage/storage_utils.h"
namespace lbug {
namespace storage {
class OverflowFile;
struct StringOverflowFileHeader {
struct Entry {
common::page_idx_t startPageIdx{common::INVALID_PAGE_IDX};
PageCursor cursor;
} entries[NUM_HASH_INDEXES];
StringOverflowFileHeader() : entries{} {}
};
static_assert(std::has_unique_object_representations_v<StringOverflowFileHeader>);
class OverflowFileHandle {
public:
OverflowFileHandle(OverflowFile& overflowFile, StringOverflowFileHeader::Entry& entry)
: startPageIdx(entry.startPageIdx), nextPosToWriteTo(entry.cursor),
overflowFile{overflowFile} {}
OverflowFileHandle(OverflowFileHandle&& other) = delete;
std::string readString(transaction::TransactionType trxType, const common::string_t& str) const;
bool equals(transaction::TransactionType trxType, std::string_view keyToLookup,
const common::string_t& keyInEntry) const;
common::string_t writeString(PageAllocator* pageAllocator, std::string_view rawString);
common::string_t writeString(PageAllocator* pageAllocator, const char* rawString) {
return writeString(pageAllocator, std::string_view(rawString));
}
void checkpoint();
void checkpointInMemory() { pageWriteCache.clear(); }
void rollbackInMemory(PageCursor nextPosToWriteTo_) {
pageWriteCache.clear();
this->nextPosToWriteTo = nextPosToWriteTo_;
}
void reclaimStorage(PageAllocator& pageAllocator);
private:
uint8_t* addANewPage(PageAllocator* pageAllocator);
void setStringOverflow(PageAllocator* pageAllocator, const char* inMemSrcStr, uint64_t len,
common::string_t& diskDstString);
void read(transaction::TransactionType trxType, common::page_idx_t pageIdx,
const std::function<void(uint8_t*)>& func) const;
private:
static constexpr common::page_idx_t END_OF_PAGE =
common::LBUG_PAGE_SIZE - sizeof(common::page_idx_t);
common::page_idx_t& startPageIdx;
PageCursor& nextPosToWriteTo;
OverflowFile& overflowFile;
struct CachedPage {
std::unique_ptr<MemoryBuffer> buffer;
bool newPage = false;
};
std::unordered_map<common::page_idx_t, CachedPage> pageWriteCache;
};
class ShadowFile;
class OverflowFile {
friend class OverflowFileHandle;
public:
OverflowFile(FileHandle* fileHandle, MemoryManager& memoryManager, ShadowFile* shadowFile,
common::page_idx_t headerPageIdx);
virtual ~OverflowFile() = default;
OverflowFile(OverflowFile&& other) = delete;
void rollbackInMemory();
void checkpoint(PageAllocator& pageAllocator);
void checkpointInMemory();
void reclaimStorage(PageAllocator& pageAllocator) const;
common::page_idx_t getHeaderPageIdx() const { return headerPageIdx; }
OverflowFileHandle* addHandle() {
DASSERT(handles.size() < NUM_HASH_INDEXES);
handles.emplace_back(
std::make_unique<OverflowFileHandle>(*this, header.entries[handles.size()]));
return handles.back().get();
}
FileHandle* getFileHandle() const {
DASSERT(fileHandle);
return fileHandle;
}
protected:
explicit OverflowFile(MemoryManager& memoryManager);
common::page_idx_t getNewPageIdx(PageAllocator* pageAllocator);
private:
void readFromDisk(transaction::TransactionType trxType, common::page_idx_t pageIdx,
const std::function<void(uint8_t*)>& func) const;
void writePageToDisk(common::page_idx_t pageIdx, uint8_t* data, bool newPage) const;
protected:
static constexpr uint64_t HEADER_PAGE_IDX = 0;
std::vector<std::unique_ptr<OverflowFileHandle>> handles;
StringOverflowFileHeader header;
FileHandle* fileHandle;
ShadowFile* shadowFile;
MemoryManager& memoryManager;
std::atomic<common::page_idx_t> pageCounter;
std::atomic<bool> headerChanged;
common::page_idx_t headerPageIdx;
};
class InMemOverflowFile final : public OverflowFile {
public:
explicit InMemOverflowFile(MemoryManager& memoryManager) : OverflowFile{memoryManager} {}
};
} }