diff --git a/db/db_impl.cc b/db/db_impl.cc index 06752aa..ffb1889 100644 --- a/db/db_impl.cc +++ b/db/db_impl.cc @@ -42,7 +42,7 @@ const int kNumNonTableCacheFiles = 10; //TTL ToDo : add func for TTL Put void AppendExpirationTime(std::string* value, uint64_t expiration_time) { - // 将过期时间戳(64位整数)附加到值的前面 + // 直接将小端序的过期时间戳(64位整数)附加到值的前面 value->append(reinterpret_cast(&expiration_time), sizeof(expiration_time)); } @@ -53,11 +53,11 @@ uint64_t GetCurrentTime() { // 解析过期时间戳 uint64_t ParseExpirationTime(const std::string& value) { - // 假设过期时间戳在值的前 8 字节,以大端序存储 + // 假设过期时间戳在值的前 8 字节 assert(value.size() >= sizeof(uint64_t)); uint64_t expiration_time; memcpy(&expiration_time, value.data(), sizeof(uint64_t)); - return expiration_time; + return expiration_time; // 直接返回小端序的值 } // 解析出实际的值(去掉前面的过期时间戳部分) @@ -1207,14 +1207,14 @@ Status DBImpl::Get(const ReadOptions& options, const Slice& key, // 如果当前时间已经超过过期时间,则认为数据过期,返回 NotFound if (current_time > expiration_time) { - s = Status::NotFound("Key expired"); + s = Status::NotFound(Slice()); } else { // 数据未过期,解析出实际的值 *value = ParseActualValue(*value); } } - //finish modify + // //finish modify if (have_stat_update && current->UpdateStats(stats)) { MaybeScheduleCompaction(); diff --git a/db/db_test.cc b/db/db_test.cc index f0af181..e04ead4 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -348,6 +348,7 @@ class DBTest : public testing::Test { Status Put(const std::string& k, const std::string& v) { return db_->Put(WriteOptions(), k, v); } + Status Delete(const std::string& k) { return db_->Delete(WriteOptions(), k); } diff --git a/db/memtable.cc b/db/memtable.cc index 4f09340..d7c4078 100644 --- a/db/memtable.cc +++ b/db/memtable.cc @@ -73,6 +73,8 @@ class MemTableIterator : public Iterator { Iterator* MemTable::NewIterator() { return new MemTableIterator(&table_); } + + void MemTable::Add(SequenceNumber s, ValueType type, const Slice& key, const Slice& value) { // Format of an entry is concatenation of: @@ -124,6 +126,23 @@ bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { case kTypeValue: { Slice v = GetLengthPrefixedSlice(key_ptr + key_length); value->assign(v.data(), v.size()); + + // TTL ToDo :检查:从 value 中解析出过期时间戳并与当前时间比较 + assert(value->size() >= sizeof(uint64_t)); + uint64_t expiration_time; + memcpy(&expiration_time, value->data(), sizeof(uint64_t)); // 解析出过期时间戳 + uint64_t current_time = static_cast(time(nullptr)); // 获取当前时间 + + // 如果当前时间已超过过期时间,设置状态为 NotFound 表示数据过期 + if (current_time > expiration_time) { + *s = Status::NotFound(Slice()); + return true; + } else { + // 数据未过期,解析出实际的值部分,去掉过期时间戳 + *value = value->substr(sizeof(uint64_t)); + } + + //finish modify return true; } case kTypeDeletion: diff --git a/test/ttl_test.cc b/test/ttl_test.cc index a8d611e..3712b25 100644 --- a/test/ttl_test.cc +++ b/test/ttl_test.cc @@ -4,7 +4,7 @@ #include "leveldb/env.h" #include "leveldb/db.h" - +#include using namespace leveldb; @@ -20,14 +20,28 @@ Status OpenDB(std::string dbName, DB **db) { void InsertData(DB *db, uint64_t ttl/* second */) { WriteOptions writeOptions; int key_num = data_size / value_size; - srand(static_cast(time(0))); + srand(42); + + // 用于存储成功写入的唯一键 + std::unordered_set unique_keys; for (int i = 0; i < key_num; i++) { int key_ = rand() % key_num+1; std::string key = std::to_string(key_); std::string value(value_size, 'a'); - db->Put(writeOptions, key, value, ttl); + Status status = db->Put(writeOptions, key, value, ttl); + if (!status.ok()) { + // 输出失败的状态信息并退出循环 + std::cerr << "Failed to write key: " << key + << ", Status: " << status.ToString() << std::endl; + }else{ + std::cerr << "Success to write key: " << key << std::endl; + unique_keys.insert(key); // 插入集合中,如果已经存在则不会重复插入 + } } + + // 打印成功写入的唯一键的数量 + std::cout << "Total unique keys successfully written: " << unique_keys.size() << std::endl; } void GetData(DB *db, int size = (1 << 30)) { @@ -35,7 +49,7 @@ void GetData(DB *db, int size = (1 << 30)) { int key_num = data_size / value_size; // 点查 - srand(static_cast(time(0))); + srand(42); for (int i = 0; i < 100; i++) { int key_ = rand() % key_num+1; std::string key = std::to_string(key_); @@ -58,12 +72,18 @@ TEST(TestTTL, ReadTTL) { ReadOptions readOptions; Status status; int key_num = data_size / value_size; - srand(static_cast(time(0))); + srand(42); for (int i = 0; i < 100; i++) { int key_ = rand() % key_num+1; std::string key = std::to_string(key_); std::string value; status = db->Get(readOptions, key, &value); + + // 检查 status 并打印出失败的状态信息 + if (!status.ok()) { + std::cerr << "Key: " << key << ", Status: " << status.ToString() << std::endl; + } + ASSERT_TRUE(status.ok()); } @@ -74,6 +94,12 @@ TEST(TestTTL, ReadTTL) { std::string key = std::to_string(key_); std::string value; status = db->Get(readOptions, key, &value); + + // 检查 status 并打印出失败的状态信息 + if (status.ok()) { + std::cerr << "Key: " << key << ", Status: " << status.ToString() << std::endl; + } + ASSERT_FALSE(status.ok()); } } @@ -106,6 +132,7 @@ TEST(TestTTL, CompactionTTL) { int main(int argc, char** argv) { + srand(42); // All tests currently run with the same read-only file limits. testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();