From 3c6c4e59a2bf94e495d0afb12f79f19c7868c1e0 Mon Sep 17 00:00:00 2001 From: jiyeoniya <2952095622@qq.com> Date: Thu, 31 Oct 2024 16:02:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84get=E5=A2=9E=E5=8A=A0TTL?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/memtable.cc | 62 +++++----------------------- db/version_set.cc | 101 ++++++++++++++++++++++++++++++++++++++++++++++ table/block.cc | 5 ++- table/table.cc | 118 +++++++++++++++++++++++++++++++++++++++++++----------- test/ttl_test.cc | 5 ++- 5 files changed, 211 insertions(+), 80 deletions(-) diff --git a/db/memtable.cc b/db/memtable.cc index f237ab5..883f5e1 100644 --- a/db/memtable.cc +++ b/db/memtable.cc @@ -100,63 +100,21 @@ void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key, table_.Insert(buf); } -// bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { //燕改 -// Slice memkey = key.memtable_key(); -// Table::Iterator iter(&table_); -// iter.Seek(memkey.data()); -// if (iter.Valid()) {// 获取跳表项的内容 -// // entry format is: -// // klength varint32 -// // userkey char[klength] -// // tag uint64 -// // vlength varint32 -// // value char[vlength] -// // Check that it belongs to same user key. We do not check the -// // sequence number since the Seek() call above should have skipped -// // all entries with overly large sequence numbers. -// const char* entry = iter.key(); -// uint32_t key_length; -// const char* key_ptr = GetVarint32Ptr(entry, entry + 5, &key_length); -// if (comparator_.comparator.user_comparator()->Compare(// 比较键值 -// Slice(key_ptr, key_length - 8), key.user_key()) == 0) { -// // Correct user key -// const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); -// switch (static_cast(tag & 0xff)) { -// case kTypeValue: { -// // Slice v = GetLengthPrefixedSlice(key_ptr + key_length); -// // value->assign(v.data(), v.size()); -// // return true; - -// // 获取过期时间戳,燕改 -// Slice v = GetLengthPrefixedSlice(key_ptr + key_length); -// uint64_t expire_time = DecodeFixed64(v.data() + v.size() - sizeof(uint64_t)); - -// // 检查是否已过期 -// uint64_t current_time = Env::Default()->NowMicros() / 1000000; // 当前时间(秒) -// if (expire_time > 0 && expire_time < current_time) { -// *s = Status::NotFound("Key has expired"); // 已过期 -// return false; -// } - -// // 未过期,返回值 -// value->assign(v.data() + 8, v.size() - 8); // 去除前8字节的时间戳 -// return true; -// } -// case kTypeDeletion: -// *s = Status::NotFound(Slice()); -// return true; -// } -// } -// } -// return false; -// } - -bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { //燕改 Slice memkey = key.memtable_key(); Table::Iterator iter(&table_); iter.Seek(memkey.data()); if (iter.Valid()) { // 获取跳表项的内容 + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. const char* entry = iter.key(); uint32_t key_length; const char* key_ptr = GetVarint32Ptr(entry, entry + 5, &key_length); diff --git a/db/version_set.cc b/db/version_set.cc index 4e37bf9..6874401 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -321,6 +321,107 @@ void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg, } } +// Status Version::Get(const ReadOptions& options, const LookupKey& k, +// std::string* value, GetStats* stats) { +// stats->seek_file = nullptr; +// stats->seek_file_level = -1; + +// struct State { +// Saver saver; +// GetStats* stats; +// const ReadOptions* options; +// Slice ikey; +// FileMetaData* last_file_read; +// int last_file_read_level; + +// VersionSet* vset; +// Status s; +// bool found; + +// static bool Match(void* arg, int level, FileMetaData* f) { +// State* state = reinterpret_cast(arg); + +// if (state->stats->seek_file == nullptr && +// state->last_file_read != nullptr) { //如果 seek_file 为空且 last_file_read 不为空 +// // We have had more than one seek for this read. Charge the 1st file. +// // 记录第一次的查找文件信息 +// state->stats->seek_file = state->last_file_read; //则记录 seek_file 以标记第一次读取的文件和层级。 +// state->stats->seek_file_level = state->last_file_read_level; +// } + +// state->last_file_read = f; //更新 last_file_read 和 last_file_read_level +// state->last_file_read_level = level; +// //调用 table_cache_->Get:从缓存中获取指定文件,并在查找键时使用 SaveValue 回调, +// state->s = state->vset->table_cache_->Get(*state->options, f->number, +// f->file_size, state->ikey, +// &state->saver, SaveValue); + + +// // 使用TableCache::Get并传递自定义的SaveValue函数以进行TTL检查,燕改 +// auto ttl_save_value = [](void* arg, const Slice& key, const Slice& value) { +// Saver* saver = reinterpret_cast(arg); +// if (value.size() < 19) { +// saver->state = kNotFound; +// return; +// } + +// // 解析时间戳并检查过期情况 +// uint64_t expire_time = DecodeFixed64(value.data() + value.size() - 19); +// if (expire_time > Env::Default()->NowMicros()) { +// SaveValue(arg, key, value); // 未过期,保存数据 +// } else { +// saver->state = kNotFound; // 数据已过期 +// } +// }; +// // 调用Get并传递自定义的ttl_save_value,燕改 +// state->s = state->vset->table_cache_->Get(*state->options, f->number, +// f->file_size, state->ikey, +// &state->saver, ttl_save_value); + +// if (!state->s.ok()) { +// return false; +// } +// switch (state->saver.state) { +// case kNotFound: +// state->found = false; // 设置为未找到,燕改 +// return true; // Keep searching in other files +// case kFound: +// state->found = true; +// return false; +// case kDeleted: +// return false; +// case kCorrupt: +// state->s = +// Status::Corruption("corrupted key for ", state->saver.user_key); +// state->found = true; +// return false; +// } + +// // Not reached. Added to avoid false compilation warnings of +// // "control reaches end of non-void function". +// return false; +// } +// }; + +// State state; +// state.found = false; +// state.stats = stats; +// state.last_file_read = nullptr; +// state.last_file_read_level = -1; + +// state.options = &options; +// state.ikey = k.internal_key(); +// state.vset = vset_; + +// state.saver.state = kNotFound; +// state.saver.ucmp = vset_->icmp_.user_comparator(); +// state.saver.user_key = k.user_key(); +// state.saver.value = value; + +// ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match); + +// return state.found ? state.s : Status::NotFound(Slice()); +// } Status Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, GetStats* stats) { stats->seek_file = nullptr; diff --git a/table/block.cc b/table/block.cc index 3b15257..314106c 100644 --- a/table/block.cc +++ b/table/block.cc @@ -180,7 +180,7 @@ class Block::Iter : public Iterator { right = restart_index_; } else { // We're seeking to the key we're already at. - return; + return;// 已找到,不需要进一步查找 } } @@ -193,9 +193,10 @@ class Block::Iter : public Iterator { &non_shared, &value_length); if (key_ptr == nullptr || (shared != 0)) { CorruptionError(); - return; + return; // 返回错误状态 } Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { // Key at "mid" is smaller than "target". Therefore all // blocks before "mid" are uninteresting. diff --git a/table/table.cc b/table/table.cc index 29e835f..073f9e4 100644 --- a/table/table.cc +++ b/table/table.cc @@ -4,6 +4,11 @@ #include "leveldb/table.h" +#include // For std::istringstream +#include // For std::get_time +#include // For std::tm and std::mktime + + #include "leveldb/cache.h" #include "leveldb/comparator.h" #include "leveldb/env.h" @@ -211,36 +216,101 @@ Iterator* Table::NewIterator(const ReadOptions& options) const { &Table::BlockReader, const_cast(this), options); } +// Status Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg, +// void (*handle_result)(void*, const Slice&, +// const Slice&)) { +// Status s; +// Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); +// iiter->Seek(k); +// if (iiter->Valid()) { +// Slice handle_value = iiter->value(); +// FilterBlockReader* filter = rep_->filter; +// BlockHandle handle; +// if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() && +// !filter->KeyMayMatch(handle.offset(), k)) { +// // Not found +// } else { +// Iterator* block_iter = BlockReader(this, options, iiter->value()); +// block_iter->Seek(k); +// if (block_iter->Valid()) { +// (*handle_result)(arg, block_iter->key(), block_iter->value()); +// } +// s = block_iter->status(); +// delete block_iter; +// } +// } +// if (s.ok()) { +// s = iiter->status(); +// } +// delete iiter; +// return s; +// } Status Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg, void (*handle_result)(void*, const Slice&, const Slice&)) { - Status s; - Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); - iiter->Seek(k); - if (iiter->Valid()) { - Slice handle_value = iiter->value(); - FilterBlockReader* filter = rep_->filter; - BlockHandle handle; - if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() && - !filter->KeyMayMatch(handle.offset(), k)) { - // Not found - } else { - Iterator* block_iter = BlockReader(this, options, iiter->value()); - block_iter->Seek(k); - if (block_iter->Valid()) { - (*handle_result)(arg, block_iter->key(), block_iter->value()); - } - s = block_iter->status(); - delete block_iter; + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + // 这里获取存储的组合字符串 + s = Status::OK(); // 确保状态为 OK + Slice combined_value = block_iter->value(); + + // 获取实际的值和过期时间 + std::string combined_str = combined_value.ToString(); + + // 假设过期时间是字符串的最后19个字符 + std::string expiration_time_str = combined_str.substr(combined_str.size() - 19, 19); // 获取过期时间字符串 + std::string actual_value = combined_str.substr(0, combined_str.size() - 19); // 获取实际值 + + // 解析过期时间为时间戳 + std::tm tm = {}; + std::istringstream ss(expiration_time_str); + ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); + std::time_t expiration_time = std::mktime(&tm); + + // 获取当前时间并与过期时间进行比较 + auto now = std::chrono::system_clock::now(); + auto now_time_t = std::chrono::system_clock::to_time_t(now); + + // 检查是否过期 + if (expiration_time > now_time_t) { + // 调用结果处理函数,返回实际值 + (*handle_result)(arg, block_iter->key(), Slice(actual_value));//, Slice(expiration_time_str)); + s = block_iter->status(); + if (! s.ok()) printf("291\n"); + } else { + // 数据已过期,处理过期情况 + s = Status::NotFound("Key has expired"); + } + } + else { + s = block_iter->status(); + if (! s.ok()) printf("299\n"); + } + delete block_iter; + } } - } - if (s.ok()) { - s = iiter->status(); - } - delete iiter; - return s; + if (s.ok()) { + s = iiter->status(); + if (! s.ok()) printf("306\n"); + } + delete iiter; + if (! s.ok()) printf("!!!!!!!!!!!"); // 如果不在sstable里 + return s; } + uint64_t Table::ApproximateOffsetOf(const Slice& key) const { Iterator* index_iter = rep_->index_block->NewIterator(rep_->options.comparator); diff --git a/test/ttl_test.cc b/test/ttl_test.cc index ba20598..1c601d6 100644 --- a/test/ttl_test.cc +++ b/test/ttl_test.cc @@ -42,7 +42,7 @@ void GetData(DB *db, int size = (1 << 30)) { int key_ = rand() % key_num+1; //int key_ = i % key_num+1; std::string key = std::to_string(key_); - std::string value; + std::string value; db->Get(readOptions, key, &value); } } @@ -54,7 +54,7 @@ TEST(TestTTL, ReadTTL) { abort(); } - uint64_t ttl = 200; + uint64_t ttl = 30; InsertData(db, ttl); @@ -81,6 +81,7 @@ TEST(TestTTL, ReadTTL) { status = db->Get(readOptions, key, &value); ASSERT_FALSE(status.ok()); } + delete db; } TEST(TestTTL, CompactionTTL) {