Skip to content

Commit d34e9f5

Browse files
authored
MemLens Database Specific Changes (#170)
* global and local build config with profiling flags. * integrated basic memory hook for RSS calculation * edited script to generate callgraph using gprof * enabling level db as default storage engine * systemd telegraf script to stream prometheus node_exporter data to InfluxDB. * added lmdb storage engine interface and partially implemented. * bootstrapping script to run perf tools * adding process exporter to bootstrapping script * Added LRU Cache and Observabiity stats * lry cache controlled using settings * removing lmdb implementation * removing unecessary scripts * Resolving comments for build flags and memory leak * resolved error. options.block_cache_ integration still not working * added UT's for TC's. removed logs from stats and changed lru implementation var names * reverting configs and removing unwanted files * removing unwanted tst logs * refactor: rename GetMetrics to UpdateMetrics and improve cache handling in ResLevelDB * feat: add LevelDB block cache support and corresponding tests. * feat: enhance LevelDB block cache with configurable capacity and update metrics return type * refactor: update transaction summary variable names for consistency * build: optimize compilation flags by adding optimization level * build: remove debugging flags from kv_service and api_tools builds * build: remove profiling flags from set_random_data binary * build: remove pyroscope monitoring from kv service startup script * build: include string header in lru_cache implementation
1 parent 035a1bb commit d34e9f5

File tree

21 files changed

+638
-25
lines changed

21 files changed

+638
-25
lines changed

.bazelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
build --cxxopt='-std=c++17' --copt=-O3 --jobs=40
1+
build --cxxopt='-std=c++17' --copt=-O3 --jobs=40
22
#build --action_env=PYTHON_BIN_PATH="/usr/bin/python3.10"
33
#build --action_env=PYTHON_LIB_PATH="/usr/include/python3.10"
44

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,10 @@ sdk_validator/venv
1313
__pycache__
1414
MODULE.*
1515
apache_release
16+
*.out.*
17+
*.data.*
18+
*.pb.*
19+
.cache/
20+
resdb/
21+
100*_db/
22+
gmon.out

WORKSPACE

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
workspace(name = "com_resdb_nexres")
22

33
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
4+
5+
http_archive(
6+
name = "hedron_compile_commands",
7+
#Replace the commit hash (4f28899228fb3ad0126897876f147ca15026151e) with the latest commit hash from the repo
8+
url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/4f28899228fb3ad0126897876f147ca15026151e.tar.gz",
9+
strip_prefix = "bazel-compile-commands-extractor-4f28899228fb3ad0126897876f147ca15026151e",
10+
)
11+
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
12+
hedron_compile_commands_setup()
13+
load("@hedron_compile_commands//:workspace_setup_transitive.bzl", "hedron_compile_commands_setup_transitive")
14+
hedron_compile_commands_setup_transitive()
15+
load("@hedron_compile_commands//:workspace_setup_transitive_transitive.bzl", "hedron_compile_commands_setup_transitive_transitive")
16+
hedron_compile_commands_setup_transitive_transitive()
17+
load("@hedron_compile_commands//:workspace_setup_transitive_transitive_transitive.bzl", "hedron_compile_commands_setup_transitive_transitive_transitive")
18+
hedron_compile_commands_setup_transitive_transitive_transitive()
19+
420
load("//:repositories.bzl", "nexres_repositories")
521

622
nexres_repositories()

chain/storage/BUILD

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ cc_library(
5252
"//chain/storage/proto:kv_cc_proto",
5353
"//chain/storage/proto:leveldb_config_cc_proto",
5454
"//common:comm",
55+
"//common/lru:lru_cache",
56+
"//platform/statistic:stats",
5557
"//third_party:leveldb",
5658
],
5759
)
@@ -64,4 +66,18 @@ cc_test(
6466
":memory_db",
6567
"//common/test:test_main",
6668
],
69+
timeout = "short", # Set the timeout to "short"
70+
size = "small", # Set the size to "small"
6771
)
72+
73+
cc_test(
74+
name = "leveldb_test",
75+
srcs = ["leveldb_test.cpp"],
76+
deps = [
77+
":leveldb",
78+
"//platform/statistic:stats",
79+
"//common/test:test_main",
80+
],
81+
timeout = "short", # Set the timeout to "short"
82+
size = "small", # Set the size to "small"
83+
)

chain/storage/kv_storage_test.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ namespace resdb {
3030
namespace storage {
3131
namespace {
3232

33-
enum StorageType {
34-
MEM = 0,
35-
LEVELDB = 1,
36-
};
33+
enum StorageType { MEM = 0, LEVELDB = 1, LEVELDB_WITH_BLOCK_CACHE = 2 };
3734

3835
class KVStorageTest : public ::testing::TestWithParam<StorageType> {
3936
protected:
@@ -47,6 +44,12 @@ class KVStorageTest : public ::testing::TestWithParam<StorageType> {
4744
Reset();
4845
storage = NewResLevelDB(path_);
4946
break;
47+
case LEVELDB_WITH_BLOCK_CACHE:
48+
Reset();
49+
LevelDBInfo config;
50+
config.set_enable_block_cache(true);
51+
storage = NewResLevelDB(path_, config);
52+
break;
5053
}
5154
}
5255

@@ -218,8 +221,16 @@ TEST_P(KVStorageTest, GetHistory) {
218221
}
219222
}
220223

224+
TEST_P(KVStorageTest, BlockCacheSpecificTest) {
225+
if (GetParam() == LEVELDB_WITH_BLOCK_CACHE) {
226+
std::cout << "Running BlockCacheSpecificTest for LEVELDB_WITH_BLOCK_CACHE"
227+
<< std::endl;
228+
}
229+
}
230+
221231
INSTANTIATE_TEST_CASE_P(KVStorageTest, KVStorageTest,
222-
::testing::Values(MEM, LEVELDB));
232+
::testing::Values(MEM, LEVELDB,
233+
LEVELDB_WITH_BLOCK_CACHE));
223234

224235
} // namespace
225236
} // namespace storage

chain/storage/leveldb.cpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
#include "chain/storage/leveldb.h"
2121

2222
#include <glog/logging.h>
23+
#include <unistd.h>
24+
25+
#include <cstdint>
2326

2427
#include "chain/storage/proto/kv.pb.h"
28+
#include "leveldb/options.h"
2529

2630
namespace resdb {
2731
namespace storage {
@@ -50,6 +54,16 @@ ResLevelDB::ResLevelDB(std::optional<LevelDBInfo> config) {
5054
path = (*config).path();
5155
}
5256
}
57+
if ((*config).enable_block_cache()) {
58+
uint32_t capacity = 1000;
59+
if ((*config).has_block_cache_capacity()) {
60+
capacity = (*config).block_cache_capacity();
61+
}
62+
block_cache_ =
63+
std::make_unique<LRUCache<std::string, std::string>>(capacity);
64+
LOG(ERROR) << "initialized block cache" << std::endl;
65+
}
66+
global_stats_ = Stats::GetGlobalStats();
5367
CreateDB(path);
5468
}
5569

@@ -74,15 +88,22 @@ ResLevelDB::~ResLevelDB() {
7488
if (db_) {
7589
db_.reset();
7690
}
91+
if (block_cache_) {
92+
block_cache_->Flush();
93+
}
7794
}
7895

7996
int ResLevelDB::SetValue(const std::string& key, const std::string& value) {
97+
if (block_cache_) {
98+
block_cache_->Put(key, value);
99+
}
80100
batch_.Put(key, value);
81101

82102
if (batch_.ApproximateSize() >= write_batch_size_) {
83103
leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch_);
84104
if (status.ok()) {
85105
batch_.Clear();
106+
UpdateMetrics();
86107
return 0;
87108
} else {
88109
LOG(ERROR) << "flush buffer fail:" << status.ToString();
@@ -93,13 +114,23 @@ int ResLevelDB::SetValue(const std::string& key, const std::string& value) {
93114
}
94115

95116
std::string ResLevelDB::GetValue(const std::string& key) {
96-
std::string value = "";
97-
leveldb::Status status = db_->Get(leveldb::ReadOptions(), key, &value);
98-
if (status.ok()) {
99-
return value;
100-
} else {
101-
return "";
117+
std::string value;
118+
bool found_in_cache = false;
119+
120+
if (block_cache_) {
121+
value = block_cache_->Get(key);
122+
found_in_cache = !value.empty();
102123
}
124+
125+
if (!found_in_cache) {
126+
leveldb::Status status = db_->Get(leveldb::ReadOptions(), key, &value);
127+
if (!status.ok()) {
128+
value.clear(); // Ensure value is empty if not found in DB
129+
}
130+
}
131+
132+
UpdateMetrics();
133+
return value;
103134
}
104135

105136
std::string ResLevelDB::GetAllValues(void) {
@@ -134,6 +165,19 @@ std::string ResLevelDB::GetRange(const std::string& min_key,
134165
return values;
135166
}
136167

168+
bool ResLevelDB::UpdateMetrics() {
169+
if (block_cache_ == nullptr) {
170+
return false;
171+
}
172+
std::string stats;
173+
std::string approximate_size;
174+
db_->GetProperty("leveldb.stats", &stats);
175+
db_->GetProperty("leveldb.approximate-memory-usage", &approximate_size);
176+
global_stats_->SetStorageEngineMetrics(block_cache_->GetCacheHitRatio(),
177+
stats, approximate_size);
178+
return true;
179+
}
180+
137181
bool ResLevelDB::Flush() {
138182
leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch_);
139183
if (status.ok()) {

chain/storage/leveldb.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525

2626
#include "chain/storage/proto/leveldb_config.pb.h"
2727
#include "chain/storage/storage.h"
28+
#include "common/lru/lru_cache.h"
2829
#include "leveldb/db.h"
2930
#include "leveldb/write_batch.h"
31+
#include "platform/statistic/stats.h"
3032

3133
namespace resdb {
3234
namespace storage {
@@ -65,6 +67,8 @@ class ResLevelDB : public Storage {
6567
std::vector<std::pair<std::string, int>> GetTopHistory(
6668
const std::string& key, int top_number) override;
6769

70+
bool UpdateMetrics();
71+
6872
bool Flush() override;
6973

7074
private:
@@ -75,6 +79,10 @@ class ResLevelDB : public Storage {
7579
::leveldb::WriteBatch batch_;
7680
unsigned int write_buffer_size_ = 64 << 20;
7781
unsigned int write_batch_size_ = 1;
82+
83+
protected:
84+
Stats* global_stats_ = nullptr;
85+
std::unique_ptr<LRUCache<std::string, std::string>> block_cache_;
7886
};
7987

8088
} // namespace storage

chain/storage/leveldb_test.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "chain/storage/leveldb.h"
21+
22+
#include <glog/logging.h>
23+
#include <gmock/gmock.h>
24+
#include <gtest/gtest.h>
25+
26+
#include <filesystem>
27+
28+
namespace resdb {
29+
namespace storage {
30+
namespace {
31+
32+
enum class CacheConfig { DISABLED, ENABLED };
33+
34+
class TestableResLevelDB : public ResLevelDB {
35+
public:
36+
using ResLevelDB::block_cache_;
37+
using ResLevelDB::global_stats_;
38+
using ResLevelDB::ResLevelDB;
39+
};
40+
41+
class LevelDBTest : public ::testing::TestWithParam<CacheConfig> {
42+
protected:
43+
LevelDBTest() {
44+
LevelDBInfo config;
45+
if (GetParam() == CacheConfig::ENABLED) {
46+
config.set_enable_block_cache(true);
47+
config.set_block_cache_capacity(1000);
48+
} else {
49+
Reset();
50+
}
51+
storage = std::make_unique<TestableResLevelDB>(config);
52+
}
53+
54+
protected:
55+
std::unique_ptr<TestableResLevelDB> storage;
56+
std::string path_ = "/tmp/leveldb_test";
57+
58+
private:
59+
void Reset() { std::filesystem::remove_all(path_.c_str()); }
60+
};
61+
62+
TEST_P(LevelDBTest, BlockCacheEnabled) {
63+
if (GetParam() == CacheConfig::ENABLED) {
64+
EXPECT_TRUE(storage->block_cache_ != nullptr);
65+
EXPECT_TRUE(storage->block_cache_->GetCapacity() == 1000);
66+
} else {
67+
EXPECT_TRUE(storage->block_cache_ == nullptr);
68+
EXPECT_FALSE(storage->UpdateMetrics());
69+
}
70+
}
71+
72+
TEST_P(LevelDBTest, AddValueAndCheckCache) {
73+
if (GetParam() == CacheConfig::ENABLED) {
74+
// Add a value
75+
std::string key = "test_key";
76+
std::string value = "test_value";
77+
EXPECT_EQ(storage->SetValue(key, value), 0);
78+
79+
// Check if CacheHit is incremented in the Stats class
80+
EXPECT_TRUE(storage->block_cache_->Get(key) == "test_value");
81+
EXPECT_EQ(storage->block_cache_->GetCacheHits(), 1);
82+
}
83+
}
84+
85+
TEST_P(LevelDBTest, CacheEvictionPolicy) {
86+
if (GetParam() == CacheConfig::ENABLED) {
87+
// Insert 1000 values
88+
for (int i = 1; i <= 1000; ++i) {
89+
std::string key = "key_" + std::to_string(i);
90+
std::string value = "value_" + std::to_string(i);
91+
EXPECT_EQ(storage->SetValue(key, value), 0);
92+
}
93+
94+
// Insert the 1001st value
95+
std::string key_1001 = "key_1001";
96+
std::string value_1001 = "value_1001";
97+
EXPECT_EQ(storage->SetValue(key_1001, value_1001), 0);
98+
99+
// Check that the 1001st value is not present in the cache
100+
EXPECT_TRUE(storage->GetValue("key_1") == "value_1");
101+
EXPECT_EQ(storage->block_cache_->GetCacheMisses(), 1);
102+
103+
// Expect key_2 to be present in cache and hence a cache hit
104+
EXPECT_TRUE(storage->GetValue("key_2") == "value_2");
105+
EXPECT_EQ(storage->block_cache_->GetCacheHits(), 1);
106+
107+
EXPECT_TRUE(storage->UpdateMetrics());
108+
}
109+
}
110+
111+
INSTANTIATE_TEST_CASE_P(LevelDBTest, LevelDBTest,
112+
::testing::Values(CacheConfig::ENABLED,
113+
CacheConfig::DISABLED));
114+
115+
} // namespace
116+
} // namespace storage
117+
} // namespace resdb

chain/storage/proto/leveldb_config.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ message LevelDBInfo {
2525
uint32 write_buffer_size_mb = 2;
2626
uint32 write_batch_size = 3;
2727
string path = 4;
28+
optional bool enable_block_cache = 5;
29+
optional uint32 block_cache_capacity = 6;
2830
}

0 commit comments

Comments
 (0)