//
|
|
// 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();
|
|
}
|
|
|