187 rader
5.5 KiB

//
// Created by 马也驰 on 2025/1/4.
//
#include "vlog_cache.h"
#include <fstream>
void VlogCache::read_data(std::string &vlog_name, std::string& value, size_t offset, size_t len) {
std::string value_part1;
std::string value_part2;
size_t offset1, len1, offset2, len2;
offset1 = offset;
if (VALUE_ACROSS_BLOCK(offset, len)) {
offset2 = ((offset+len) / BLOCK_SIZE) * BLOCK_SIZE;
// offset2 = ((offset+len) & ~(size_t)BLOCK_SIZE);
len1 = offset2 - offset1;
len2 = offset1 + len - offset2;
} else {
len1 = len;
offset2 = offset1 + len;
len2 = 0;
}
read_data_inblock(vlog_name, value_part1, offset1, len1);
read_data_inblock(vlog_name, value_part2, offset2, len2);
value = value_part1 + value_part2;
}
void VlogCache::write_data(std::string &vlog_name, std::string& value, size_t offset, size_t len) {
std::string value_part1;
std::string value_part2;
size_t offset1, len1, offset2, len2;
offset1 = offset;
if (VALUE_ACROSS_BLOCK(offset, len)) {
// FIXME: compute correct offset2
offset2 = ((offset+len) / BLOCK_SIZE) * BLOCK_SIZE;
// offset2 = ((offset+len) & ~(size_t)BLOCK_SIZE);
len1 = offset2 - offset1;
len2 = offset1 + len - offset2;
} else {
len1 = len;
offset2 = 0;
len2 = 0;
}
const char *data = value.data();
value_part1 = std::string(data, len1);
value_part2 = std::string(&data[len1], len2);
write_data_inblock(vlog_name, value_part1, offset1, len1);
write_data_inblock(vlog_name, value_part2, offset2, len2);
}
uint16_t VlogCache::delete_data(std::string &vlog_name, size_t offset) {
uint16_t value_size;
std::string value_size_str;
read_data(vlog_name, value_size_str, offset, sizeof(uint16_t));
memcpy(&value_size, value_size_str.data(), sizeof(uint16_t));
if (value_size & DATA_DELE_MASK) {
return value_size & DATA_SIZE_MASK;
}
assert(!(value_size & DATA_DELE_MASK));
uint16_t masked_value_size = value_size | (uint16_t)DATA_DELE_MASK;
value_size_str = std::string((char *)&masked_value_size, sizeof(uint16_t));
write_data(vlog_name, value_size_str, offset, sizeof(uint16_t));
return value_size;
}
void VlogCache::read_data_inblock(std::string &vlog_name, std::string& value, size_t offset, size_t len) {
if (len == 0) return ;
auto block_num = offset_2_blocknum(offset);
auto block_offset = offset_2_inblock_offset(offset);
// auto vlog_handler = std::fstream(vlog_name, std::ios::in | std::ios::out);
auto blk_frame = block_frames[block_num];
auto frame_info_ptr = &blk_frame->frame_info_;
blk_frame->mtx.lock();
frame_info_ptr->info_latch_.lock();
if (!frame_info_ptr->cache_hit(vlog_name, block_num)) {
// cache miss
// swap old page
if (frame_info_ptr->used && frame_info_ptr->is_dirty) {
write_back_block(block_num);
}
// read new page
read_in_block(block_num, vlog_name, offset/BLOCK_SIZE);
// update frame info
frame_info_ptr->used = true;
frame_info_ptr->vlog_name = vlog_name;
frame_info_ptr->vlog_block_num = offset / BLOCK_SIZE;
frame_info_ptr->is_dirty = false;
}
value = std::string(&blk_frame->block_buff[block_offset], len);
frame_info_ptr->info_latch_.unlock();
blk_frame->mtx.unlock();
}
void VlogCache::write_data_inblock(std::string &vlog_name, std::string& value, size_t offset, size_t len) {
if (len == 0) return ;
auto block_num = offset_2_blocknum(offset);
auto block_offset = offset_2_inblock_offset(offset);
// auto vlog_handler = std::fstream(vlog_name, std::ios::in | std::ios::out);
auto blk_frame = block_frames[block_num];
auto frame_info_ptr = &blk_frame->frame_info_;
blk_frame->mtx.lock();
frame_info_ptr->info_latch_.lock();
if (!frame_info_ptr->cache_hit(vlog_name, block_num)) {
// cache miss
// swap old page
if (frame_info_ptr->used && frame_info_ptr->is_dirty) {
write_back_block(block_num);
}
// read new page
read_in_block(block_num, vlog_name, offset/BLOCK_SIZE);
// update frame info
frame_info_ptr->used = true;
frame_info_ptr->vlog_name = vlog_name;
frame_info_ptr->vlog_block_num = offset / BLOCK_SIZE;
}
memcpy(&blk_frame->block_buff[block_offset], value.c_str(), len);
frame_info_ptr->is_dirty = true;
frame_info_ptr->info_latch_.unlock();
blk_frame->mtx.unlock();
}
void VlogCache::flush_all_blocks() {
for (auto i = 0; i < BLOCK_NUMS; i++) {
auto blk_frame = block_frames[i];
auto frame_info_ptr = &blk_frame->frame_info_;
blk_frame->mtx.lock();
frame_info_ptr->info_latch_.lock();
if (frame_info_ptr->used && frame_info_ptr->is_dirty) {
write_back_block(i);
}
blk_frame->mtx.unlock();
frame_info_ptr->info_latch_.unlock();
}
}
void VlogCache::write_back_block(size_t block_num) {
auto frame_info_ptr = &block_frames[block_num]->frame_info_;
auto vlog_handler = std::fstream(frame_info_ptr->vlog_name, std::ios::in | std::ios::out);
if (!vlog_handler.is_open()) return ;
vlog_handler.seekp(frame_info_ptr->vlog_block_num*BLOCK_SIZE);
vlog_handler.write(block_frames[block_num]->block_buff, BLOCK_SIZE);
vlog_handler.flush();
vlog_handler.close();
}
void VlogCache::read_in_block(size_t block_num, std::string& vlog_name,
size_t vlog_block_num) {
auto vlog_handler = std::fstream(vlog_name, std::ios::in | std::ios::out);
if (!vlog_handler.is_open()) return ;
vlog_handler.seekp(vlog_block_num*BLOCK_SIZE);
vlog_handler.read(block_frames[block_num]->block_buff, BLOCK_SIZE);
vlog_handler.close();
}