19 #include "../../Shared/File.h"
29 namespace File_Namespace {
34 const size_t pageSize,
37 : fileMgr(fileMgr), fileId(fileId), f(f), pageSize(pageSize), numPages(numPages) {
54 int32_t headerSize = 0;
55 int8_t* headerSizePtr = (int8_t*)(&headerSize);
56 for (
size_t pageId = 0; pageId <
numPages; ++pageId) {
63 size_t FileInfo::write(
const size_t offset,
const size_t size,
const int8_t* buf) {
80 int32_t oldPageId = -99;
81 int32_t oldVersionEpoch = -99;
83 for (
size_t pageNum = 0; pageNum <
numPages; ++pageNum) {
87 constexpr
size_t MAX_INTS_TO_READ{10};
88 int32_t ints[MAX_INTS_TO_READ];
90 CHECK_EQ(fread(ints,
sizeof(int32_t), MAX_INTS_TO_READ,
f), MAX_INTS_TO_READ);
92 auto headerSize = ints[0];
93 if (headerSize == 0) {
101 size_t numHeaderElems = headerSize /
sizeof(int32_t);
102 CHECK_GE(numHeaderElems,
size_t(2));
105 ChunkKey chunkKey(&ints[1], &ints[1 + numHeaderElems - 2]);
111 int32_t pageId = ints[1 + numHeaderElems - 2];
112 int32_t versionEpoch = ints[1 + numHeaderElems - 1];
113 if (chunkKey != oldChunkKey || oldPageId != pageId - (1 + skipped)) {
115 VLOG(4) <<
"FId.PSz: " <<
fileId <<
"." << pageSize
117 <<
" Page id from : " << oldPageId <<
" to : " << oldPageId + skipped
118 <<
" Epoch: " << oldVersionEpoch;
119 }
else if (oldPageId != -99) {
120 VLOG(4) <<
"FId.PSz: " <<
fileId <<
"." << pageSize
121 <<
" Chunk key: " <<
show_chunk(oldChunkKey) <<
" Page id: " << oldPageId
122 <<
" Epoch: " << oldVersionEpoch;
125 oldVersionEpoch = versionEpoch;
126 oldChunkKey = chunkKey;
138 int32_t fileMgrEpoch =
140 if (versionEpoch > fileMgrEpoch) {
147 <<
" Page id: " << pageId <<
" Epoch: " << versionEpoch
148 <<
" FileMgrEpoch " << fileMgrEpoch << endl;
152 headerVec.emplace_back(chunkKey, pageId, versionEpoch, page);
156 if (oldPageId != -99) {
160 <<
" Page id from : " << oldPageId <<
" to : " << oldPageId + skipped
161 <<
" Epoch: " << oldVersionEpoch;
164 <<
" Chunk key: " <<
show_chunk(oldChunkKey) <<
" Page id: " << oldPageId
165 <<
" Epoch: " << oldVersionEpoch;
175 #ifdef ENABLE_CRASH_CORRUPTION_TEST
176 #warning "!!!!! DB corruption crash test is enabled !!!!!"
178 static bool goto_crash;
179 static void sighandler(
int sig) {
180 if (getenv(
"ENABLE_CRASH_CORRUPTION_TEST"))
192 pageId *
pageSize +
sizeof(int32_t),
193 sizeof(epoch_freed_page),
194 reinterpret_cast<const int8_t*>(epoch_freed_page));
198 #ifdef ENABLE_CRASH_CORRUPTION_TEST
199 signal(SIGUSR2, sighandler);
201 CHECK(pageId % 8 != 4);
212 int32_t pageNum = *pageIt;
218 std::stringstream ss;
219 ss <<
"File: " <<
fileId << std::endl;
220 ss <<
"Size: " <<
size() << std::endl;
221 ss <<
"Used: " <<
used() << std::endl;
222 ss <<
"Free: " <<
available() << std::endl;
229 if (fflush(
f) != 0) {
230 LOG(
FATAL) <<
"Error trying to flush changes to disk, the error was: "
231 << std::strerror(errno);
234 const int32_t sync_result = fcntl(fileno(
f), 51);
238 if (sync_result == 0) {
253 f, page_num *
pageSize,
sizeof(int32_t), reinterpret_cast<const int8_t*>(&zero));
265 page_num *
pageSize +
sizeof(int32_t),
267 reinterpret_cast<const int8_t*>(chunk_key.data()));
273 int32_t contingent) {
274 const bool delete_contingent =
277 if (delete_contingent && (table_epoch >= page_epoch)) {
285 int32_t contingent) {
286 const bool delete_contingent =
289 if (delete_contingent && (table_epoch < page_epoch)) {
virtual int32_t epoch(int32_t db_id, int32_t tb_id) const
Returns current value of epoch - should be one greater than recorded at last checkpoint. Because FileMgr only contains buffers from one table we can just return the FileMgr's epoch instead of finding a table-specific epoch.
std::vector< int > ChunkKey
size_t write(const size_t offset, const size_t size, const int8_t *buf)
bool is_page_deleted_without_checkpoint(int32_t table_epoch, int32_t page_epoch, int32_t contingent)
A logical page (Page) belongs to a file on disk.
std::mutex readWriteMutex_
void freePageImmediate(int32_t page_num)
This file includes the class specification for the FILE manager (FileMgr), and related data structure...
std::string print() const
Prints a summary of the file to stdout.
virtual bool updatePageIfDeleted(FileInfo *file_info, ChunkKey &chunk_key, int32_t contingent, int32_t page_epoch, int32_t page_num)
deletes or recovers a page based on last checkpointed epoch.
std::string show_chunk(const ChunkKey &key)
void freePage(int32_t pageId, const bool isRolloff, int32_t epoch)
size_t write(FILE *f, const size_t offset, const size_t size, const int8_t *buf)
Writes the specified number of bytes to the offset position in file f from buf.
std::set< size_t > freePages
size_t pageSize
file stream object for the represented file
size_t read(FILE *f, const size_t offset, const size_t size, int8_t *buf)
Reads the specified number of bytes from the offset position in file f into buf.
constexpr int32_t DELETE_CONTINGENT
A FileInfo type has a file pointer and metadata about a file.
void init(LogOptions const &log_opts)
size_t used() const
Returns the amount of used bytes; size() - available()
void initNewFile()
Adds all pages to freePages and zeroes first four bytes of header.
size_t size() const
Returns the number of bytes used by the file.
#define CHUNK_KEY_TABLE_IDX
std::mutex freePagesMutex_
set of page numbers of free pages
constexpr int32_t ROLLOFF_CONTINGENT
size_t read(const size_t offset, const size_t size, int8_t *buf)
bool is_page_deleted_with_checkpoint(int32_t table_epoch, int32_t page_epoch, int32_t contingent)
virtual void free_page(std::pair< FileInfo *, int32_t > &&page)
FILE * f
unique file identifier (i.e., used for a file name)
This file contains the declaration and definition of a Page type and a MultiPage type.
void openExistingFile(std::vector< HeaderInfo > &headerVec)
void recoverPage(const ChunkKey &chunk_key, int32_t page_num)
void close(FILE *f)
Closes the file pointed to by the FILE pointer.
void freePageDeferred(int32_t pageId)
size_t available() const
Returns the number of free bytes available.
size_t numPages
the fixed size of each page in the file
bool isDirty
the number of pages in the file