19 #include "../../Shared/File.h"
26 namespace File_Namespace {
31 const size_t pageSize,
34 : fileMgr(fileMgr), fileId(fileId), f(f), pageSize(pageSize), numPages(numPages) {
51 int32_t headerSize = 0;
52 int8_t* headerSizePtr = (int8_t*)(&headerSize);
53 for (
size_t pageId = 0; pageId <
numPages; ++pageId) {
60 size_t FileInfo::write(
const size_t offset,
const size_t size,
const int8_t* buf) {
77 int32_t oldPageId = -99;
78 int32_t oldVersionEpoch = -99;
80 for (
size_t pageNum = 0; pageNum <
numPages; ++pageNum) {
84 constexpr
size_t MAX_INTS_TO_READ{10};
85 int32_t ints[MAX_INTS_TO_READ];
87 CHECK_EQ(fread(ints,
sizeof(int32_t), MAX_INTS_TO_READ,
f), MAX_INTS_TO_READ);
89 auto headerSize = ints[0];
90 if (headerSize == 0) {
98 size_t numHeaderElems = headerSize /
sizeof(int32_t);
102 ChunkKey chunkKey(&ints[1], &ints[1 + numHeaderElems - 2]);
108 int32_t pageId = ints[1 + numHeaderElems - 2];
109 int32_t versionEpoch = ints[1 + numHeaderElems - 1];
110 if (chunkKey != oldChunkKey || oldPageId != pageId - (1 + skipped)) {
112 VLOG(4) <<
"FId.PSz: " <<
fileId <<
"." << pageSize
114 <<
" Page id from : " << oldPageId <<
" to : " << oldPageId + skipped
115 <<
" Epoch: " << oldVersionEpoch;
116 }
else if (oldPageId != -99) {
117 VLOG(4) <<
"FId.PSz: " <<
fileId <<
"." << pageSize
118 <<
" Chunk key: " <<
show_chunk(oldChunkKey) <<
" Page id: " << oldPageId
119 <<
" Epoch: " << oldVersionEpoch;
122 oldVersionEpoch = versionEpoch;
123 oldChunkKey = chunkKey;
135 int32_t fileMgrEpoch =
137 if (versionEpoch > fileMgrEpoch) {
144 <<
" Page id: " << pageId <<
" Epoch: " << versionEpoch
145 <<
" FileMgrEpoch " << fileMgrEpoch << endl;
148 headerVec.emplace_back(chunkKey, pageId, versionEpoch, page);
152 if (oldPageId != -99) {
156 <<
" Page id from : " << oldPageId <<
" to : " << oldPageId + skipped
157 <<
" Epoch: " << oldVersionEpoch;
160 <<
" Chunk key: " <<
show_chunk(oldChunkKey) <<
" Page id: " << oldPageId
161 <<
" Epoch: " << oldVersionEpoch;
171 #ifdef ENABLE_CRASH_CORRUPTION_TEST
172 #warning "!!!!! DB corruption crash test is enabled !!!!!"
174 static bool goto_crash;
175 static void sighandler(
int sig) {
176 if (getenv(
"ENABLE_CRASH_CORRUPTION_TEST"))
188 pageId *
pageSize +
sizeof(int32_t),
189 sizeof(epoch_freed_page),
190 reinterpret_cast<const int8_t*>(epoch_freed_page));
194 #ifdef ENABLE_CRASH_CORRUPTION_TEST
195 signal(SIGUSR2, sighandler);
197 CHECK(pageId % 8 != 4);
208 int32_t pageNum = *pageIt;
214 std::cout <<
"File: " <<
fileId << std::endl;
215 std::cout <<
"Size: " <<
size() << std::endl;
216 std::cout <<
"Used: " <<
used() << std::endl;
217 std::cout <<
"Free: " <<
available() << std::endl;
225 if (fflush(
f) != 0) {
226 LOG(
FATAL) <<
"Error trying to flush changes to disk, the error was: "
227 << std::strerror(errno);
230 const int32_t sync_result = fcntl(fileno(
f), 51);
234 if (sync_result == 0) {
249 f, page_num *
pageSize,
sizeof(int32_t), reinterpret_cast<const int8_t*>(&zero));
261 page_num *
pageSize +
sizeof(int32_t),
263 reinterpret_cast<const int8_t*>(chunk_key.data()));
269 int32_t contingent) {
270 const bool delete_contingent =
273 if (delete_contingent && (table_epoch >= page_epoch)) {
281 int32_t contingent) {
282 const bool delete_contingent =
285 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)
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)
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)
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 used()
Returns the amount of used bytes; size() - available()
void print(bool pagesummary)
Prints a summary of the file to stdout.
size_t numPages
the fixed size of each page in the file
bool isDirty
the number of pages in the file
size_t available()
Returns the number of free bytes available.