Repository: veritross/YCSB-cpp
Pull request #5: feat!: setup build env for kvssd and add skeleton code for kvssd-hashmap interface (re-request)
Author: login: easter423
Labels: name: enhancement
description: New feature or request
Created: 2024-12-01T16:21:22Z | Merged: 2025-04-27T05:05:02Z

# Summary
YCSB 내 KVSSD 빌드 환경 구성 및 KVSSD 호환 인터페이스 스켈레톤 코드 작성

# Changelog
- LMDB 코드를 사용하여 KVSSD 전용 빌드 환경 구축 (```YCSB-cpp/kvssd```)
- ```std::unordered_map```을 활용한 KVSSD 호환 인터페이스 스켈레톤 코드 작성
    - 구현 파일: ```YCSB-cpp/kvssd/kvssd_hashmap_db.h```, ```YCSB-cpp/kvssd/kvssd_hashmap_db.cc```
    - 실행 파일: ```YCSB-cpp/kvssd/kvssd_hashmap_db_run.cc```
- 스켈레톤 코드 작동 테스트 완료
    - 실행 코드: ```g++ -o kvssd ./kvssd_hashmap_db_run.cc ./kvssd_hashmap_db.cc``` -> ```./kvssd```

# TODO
- [x] db api 함수 구현 (```Read, Insert, Update, Delete```)
- [x] kvs_value 변수 시각화 함수 구현 (serialize된 ```void* value```에서 값을 확인할 수 있도록)
- [x] 메모리 할당 및 해제 테스트
- [x] db api 함수 작동 테스트

# Attachments
- UML Diagram for kvssd_hashmap interface
![image](https://github.com/user-attachments/assets/6a4388ba-ce36-419b-9036-b6ff82d383d3)

# Refs
- #2 


Diff:
diff --git a/.gitignore b/.gitignore
index 50f9d154..e6729be3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,9 +2,14 @@
 *.d
 
 ycsb
+result.load
 
 .vimrc
 tags
 compile_commands.json
 .clangd/
 .cache/
+
+build
+googletest-1.15.2
+.vscode/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c6fa9c3..9b865f7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,7 @@ endif()
 
 option(BIND_ROCKSDB "build with rocksdb" OFF)
 option(BIND_LMDB "build with lmdb" OFF)
+option(BIND_KVSSD "build with kvssd" OFF)
 option(BIND_LEVELDB "build with leveldb" OFF)
 option(BIND_WIREDTIGER "build with wiredtiger" OFF)
 
@@ -84,6 +85,14 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+else()
+    message(STATUS "BIND_KVSSD - OFF")
+endif()
+
 if (BIND_LEVELDB)
     message(STATUS "BIND_LEVELDB - ON")
     file(GLOB_RECURSE YCSB_LEVELDB_SRC "leveldb/*.cc")
diff --git a/Makefile b/Makefile
index 86b27310..2dfc6399 100644
--- a/Makefile
+++ b/Makefile
@@ -16,21 +16,22 @@ BIND_LEVELDB ?= 0
 BIND_ROCKSDB ?= 0
 BIND_LMDB ?= 0
 BIND_SQLITE ?= 0
+BIND_KVSSD ?= 1
 
 # Extra options
-DEBUG_BUILD ?=
+DEBUG_BUILD ?= 
 EXTRA_CXXFLAGS ?=
 EXTRA_LDFLAGS ?=
 
 # HdrHistogram for tail latency report
-BIND_HDRHISTOGRAM ?= 1
+BIND_HDRHISTOGRAM ?= 
 # Build and statically link library, submodule required
-BUILD_HDRHISTOGRAM ?= 1
+BUILD_HDRHISTOGRAM ?= 
 
 #----------------------------------------------------------
 
 ifeq ($(DEBUG_BUILD), 1)
-	CXXFLAGS += -g
+	CXXFLAGS += -g -fsanitize=address
 else
 	CXXFLAGS += -O2
 	CPPFLAGS += -DNDEBUG
@@ -61,6 +62,10 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+	SOURCES += $(wildcard kvssd/*.cc)
+endif
+
 CXXFLAGS += -std=c++17 -Wall -pthread $(EXTRA_CXXFLAGS) -I./
 LDFLAGS += $(EXTRA_LDFLAGS) -lpthread
 SOURCES += $(wildcard core/*.cc)
diff --git a/kvssd/CMakeLists.txt b/kvssd/CMakeLists.txt
new file mode 100644
index 00000000..38db96cc
--- /dev/null
+++ b/kvssd/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.10)
+project(hashmap-kvssd)
+set(CMAKE_CXX_STANDARD 17)
+enable_testing()
+
+set(CMAKE_BUILD_TYPE Release)
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        )
+        
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g")
+        
+set(TARGET_APP kvssd_test)
+set(SrcLib SrcLib)
+set(SrcFiles kvssd_hashmap_db_impl.cc kvssd_hashmap_db.cc kvssd.cc)
+
+add_library(${SrcLib} STATIC ${SrcFiles})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+add_subdirectory(googletest-1.15.2)
+add_executable(${TARGET_APP} test/kvssd_test.cc)
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+target_link_libraries(${TARGET_APP} gtest_main ${SrcLib})
+
+include(GoogleTest)
+gtest_discover_tests(${TARGET_APP})
+
+find_program(VALGRIND "valgrind")
+if(VALGRIND)
+    add_test(NAME memcheck_specific_test
+             COMMAND ${VALGRIND}
+                     --tool=memcheck
+                     --leak-check=full
+                     --show-reachable=yes
+                     $<TARGET_FILE:${TARGET_APP}>
+                     --gtest_filter=KvssdHashMapDbImplTest.ReadSmall)
+endif()
\ No newline at end of file
diff --git a/kvssd/CMakePresets.json b/kvssd/CMakePresets.json
new file mode 100644
index 00000000..cb7cb68d
--- /dev/null
+++ b/kvssd/CMakePresets.json
@@ -0,0 +1,18 @@
+{
+    "version": 8,
+    "configurePresets": [
+        {
+            "name": "GCC 11.4.0 x86_64-linux-gnu",
+            "displayName": "KVSSD-test-build",
+            "generator": "Ninja",
+            "description": "KVSSD-test: C = /usr/bin/gcc, CXX = /usr/bin/g++",
+            "binaryDir": "${sourceDir}/build",
+            "cacheVariables": {
+                "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
+                "CMAKE_C_COMPILER": "/usr/bin/gcc",
+                "CMAKE_CXX_COMPILER": "/usr/bin/g++",
+                "CMAKE_BUILD_TYPE": "Release"
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/kvssd/kvssd.cc b/kvssd/kvssd.cc
new file mode 100644
index 00000000..6e43be7f
--- /dev/null
+++ b/kvssd/kvssd.cc
@@ -0,0 +1,57 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    //TODO
+    // if (backend == "kvssd") {
+    //     ret = new kvssd::KVSSD();
+    // }
+    return ret;
+}
+
+const bool registered = ycsbc::DBFactory::RegisterDB("kvssd", NewKvssdDB);
diff --git a/kvssd/kvssd.h b/kvssd/kvssd.h
new file mode 100644
index 00000000..29748936
--- /dev/null
+++ b/kvssd/kvssd.h
@@ -0,0 +1,108 @@
+#ifndef YCSB_C_KVSSD_H_
+#define YCSB_C_KVSSD_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "core/db_factory.h"
+#include "kvssd_const.h"
+
+namespace kvssd {
+
+enum class kvs_result {
+    KVS_SUCCESS = 0,                // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,   // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,  // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,  // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,    // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,       // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,       // index is not valid
+    KVS_ERR_KS_NAME = 0x007,        // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,   // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,    // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,        // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID =
+        0x00B,                           // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,        // the maximum number of iterators that a
+                                         // device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,  // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,       // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,  // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,       // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,      // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,       // null input parameter
+    KVS_ERR_SYS_IO = 0x013,              // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,  // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,  // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED =
+        0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017,  // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,            // device was not opened yet
+};
+
+inline const char *kvstrerror[] =  // kvs_result as index, Error statement as value
+    {
+        "Successful",                            // KVS_SUCCESS
+        "Buffer space is not enough",            // KVS_ERR_BUFFER_SMALL
+        "Device does not have enough space",     // KVS_ERR_DEV_CAPAPCITY
+        "No device with the dev_hd exists",      // KVS_ERR_DEV_NOT_EXIST
+        "Key space does not have enough space",  // KVS_ERR_KS_CAPACITY
+        "Key space is already created",          // KVS_ERR_KS_EXIST
+        "Index is not valid",                    // KVS_ERR_KS_INDEX
+        "Key space name is not valid",           // KVS_ERR_KS_NAME
+        "Key space does not exist",              // KVS_ERR_KS_NOT_EXIST
+        "Key space does not open",               // KVS_ERR_KS_NOT_OPEN
+        "Key space is already opened",           // KVS_ERR_KS_OPEN
+        "Iterator filter is not valid",          // KVS_ERR_ITERATOR_FILTER_INVALID
+        "Maximum number of iterators opened",    // KVS_ERR_ITERATOR_MAX
+        "Iterator Key Group does not exist",     // KVS_ERR_ITERATOR_NOT_EXIST
+        "Iterator is already opened",            // KVS_ERR_ITERATOR_OPEN
+        "Key is not valid",                      // KVS_ERR_KEY_LENGTH_INVALID
+        "Key does not exist",                    // KVS_ERR_KEY_NOT_EXIST
+        "Option is not supported",               // KVS_ERR_OPTION_INVALID
+        "Null input parameter",                  // KVS_ERR_PARAM_INVALID
+        "I/O error occurs",                      // KVS_ERR_SYS_IO
+        "Value length is out of range",          // KVS_ERR_VALUE_LENGTH_INVALID
+        "Value offset is out of range",          // KVS_ERR_VALUE_OFFSET_INVALID
+        "Value offset is misaligned",            // KVS_ERR_VALUE_OFFSET_MISALIGNED
+        "Value update is not allowed",           // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+        "Device was not opened yet"              // KVS_ERR_DEV_NOT_OPENED
+};
+
+struct kvs_key {
+    void *key;
+    uint16_t length;
+
+    bool operator==(const kvs_key &other) const {
+        return length == other.length && std::memcmp(key, other.key, length) == 0;
+    }
+};
+
+struct kvs_value {
+    void *value;                 // value byte stream buffer's start address
+    uint32_t length;             // value byte stream buffer size (byte)
+    uint32_t actual_value_size;  // device stored value's actual size (byte)
+    uint32_t offset;             // [optional] device stored value offset (byte)
+};
+
+class KVSSD {
+   public:
+    KVSSD() = default;
+    virtual ~KVSSD() = default;
+
+    virtual kvs_result Read(const kvs_key &, kvs_value &) = 0;
+    virtual kvs_result Insert(const kvs_key &, const kvs_value &) = 0;
+    virtual kvs_result Update(const kvs_key &, const kvs_value &) = 0;
+    virtual kvs_result Delete(const kvs_key &) = 0;
+};
+
+}  // namespace kvssd
+
+ycsbc::DB *NewKvssdDB();
+
+#endif  // YCSB_C_KVSSD_H_
\ No newline at end of file
diff --git a/kvssd/kvssd.properties b/kvssd/kvssd.properties
new file mode 100644
index 00000000..0b8ac37c
--- /dev/null
+++ b/kvssd/kvssd.properties
@@ -0,0 +1,7 @@
+kvssd.dbpath=/tmp/ycsb-kvssd
+kvssd.mapsize=1073741824
+kvssd.nosync=true
+kvssd.nometasync=false
+kvssd.noreadahead=false
+kvssd.writemap=false
+kvssd.mapasync=false
diff --git a/kvssd/kvssd_const.h b/kvssd/kvssd_const.h
new file mode 100644
index 00000000..d35416a3
--- /dev/null
+++ b/kvssd/kvssd_const.h
@@ -0,0 +1,11 @@
+#ifndef KVS_CONST_H
+#define KVS_CONST_H
+
+#define KVS_MIN_KEY_LENGTH 4
+#define KVS_MAX_KEY_LENGTH 255
+#define KVS_MIN_VALUE_LENGTH 0
+#define KVS_MAX_VALUE_LENGTH (2 * 1024 * 1024)
+#define KVS_ALIGNMENT_UNIT 512            /*value of KVS_ALIGNMENT_UNIT must be a power of 2 currently */
+#define KVS_VALUE_LENGTH_ALIGNMENT_UNIT 4 /*value of KV_VALUE_LENGTH_ALIGNMENT_UNIT must be a power of 2 currently */
+
+#endif // KVS_CONST_H
\ No newline at end of file
diff --git a/kvssd/kvssd_hashmap_db.cc b/kvssd/kvssd_hashmap_db.cc
new file mode 100644
index 00000000..b4389669
--- /dev/null
+++ b/kvssd/kvssd_hashmap_db.cc
@@ -0,0 +1,143 @@
+#include "kvssd_hashmap_db.h"
+
+#include <string>
+
+namespace kvssd_hashmap {
+
+Hashmap_KVSSD::Hashmap_KVSSD() { pthread_rwlock_init(&rwl, NULL); }
+Hashmap_KVSSD::~Hashmap_KVSSD() {
+    pthread_rwlock_wrlock(&rwl);
+    for (auto &it : db) {
+        if (it.first.key != nullptr) {
+            free(it.first.key);
+        }
+        if (it.second.value != nullptr) {
+            free(it.second.value);
+        }
+    }
+    db.clear();
+    pthread_rwlock_unlock(&rwl);
+    pthread_rwlock_destroy(&rwl);
+}
+
+kvssd::kvs_result Hashmap_KVSSD::ValidateRequest(
+    const kvssd::kvs_key &key,
+    std::optional<std::reference_wrapper<const kvssd::kvs_value>> value) {
+    if (key.length < KVS_MIN_KEY_LENGTH || KVS_MAX_KEY_LENGTH < key.length) {
+        return kvssd::kvs_result::KVS_ERR_KEY_LENGTH_INVALID;
+    }
+    if (key.key == NULL) {
+        return kvssd::kvs_result::KVS_ERR_PARAM_INVALID;
+    }
+    if (value) {
+        if (value->get().length < KVS_MIN_VALUE_LENGTH ||
+            KVS_MAX_VALUE_LENGTH < value->get().length) {
+            return kvssd::kvs_result::KVS_ERR_KEY_LENGTH_INVALID;
+        }
+        if (value->get().offset & (KVS_ALIGNMENT_UNIT - 1)) {
+            return kvssd::kvs_result::KVS_ERR_VALUE_OFFSET_MISALIGNED;
+        }
+        if (value->get().value == NULL && value->get().length) {
+            return kvssd::kvs_result::KVS_ERR_PARAM_INVALID;
+        }
+    }
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_key Hashmap_KVSSD::DeepCopyKey(const kvssd::kvs_key &orig) {
+    kvssd::kvs_key copy;
+    copy.length = orig.length;
+    copy.key = malloc(orig.length);
+    if (copy.key && orig.key) {
+        std::memcpy(copy.key, orig.key, orig.length);
+    }
+    return copy;
+}
+
+kvssd::kvs_value Hashmap_KVSSD::DeepCopyValue(const kvssd::kvs_value &orig) {
+    kvssd::kvs_value copy;
+    copy.length = orig.length;
+    copy.actual_value_size = orig.actual_value_size;
+    copy.offset = orig.offset;
+    copy.value = malloc(orig.length);
+    if (copy.value && orig.value) {
+        std::memcpy(copy.value, orig.value, orig.length);
+    }
+    return copy;
+}
+
+// API Functions
+kvssd::kvs_result Hashmap_KVSSD::Read(const kvssd::kvs_key &key, kvssd::kvs_value &value_out) {
+    kvssd::kvs_result ret = ValidateRequest(key, value_out);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_rdlock(&rwl);
+    auto it = db.find(key);
+    pthread_rwlock_unlock(&rwl);
+    if (it == db.end()) {
+        return kvssd::kvs_result::KVS_ERR_KS_NOT_EXIST;
+    }
+    value_out = DeepCopyValue(it->second);
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_result Hashmap_KVSSD::Insert(const kvssd::kvs_key &key, const kvssd::kvs_value &value) {
+    kvssd::kvs_result ret = ValidateRequest(key, value);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_wrlock(&rwl);
+    auto it = db.find(key);
+    if (it != db.end()) {
+        pthread_rwlock_unlock(&rwl);
+        return kvssd::kvs_result::KVS_ERR_KS_EXIST;
+    }
+    kvssd::kvs_key key_copy = DeepCopyKey(key);
+    kvssd::kvs_value value_copy = DeepCopyValue(value);
+
+    db.insert({key_copy, value_copy});
+    pthread_rwlock_unlock(&rwl);
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_result Hashmap_KVSSD::Update(const kvssd::kvs_key &key, const kvssd::kvs_value &value) {
+    kvssd::kvs_result ret = ValidateRequest(key, value);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_wrlock(&rwl);
+    auto it = db.find(key);
+    if (it == db.end()) {
+        pthread_rwlock_unlock(&rwl);
+        return kvssd::kvs_result::KVS_ERR_KS_NOT_EXIST;
+    }
+
+    if (it->second.value != nullptr) {
+        free(it->second.value);
+        it->second.value = nullptr;
+    }
+
+    kvssd::kvs_value value_copy = DeepCopyValue(value);
+    it->second = value_copy;
+    pthread_rwlock_unlock(&rwl);
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_result Hashmap_KVSSD::Delete(const kvssd::kvs_key &key) {
+    kvssd::kvs_result ret = ValidateRequest(key, std::nullopt);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_wrlock(&rwl);
+    auto it = db.find(key);
+    if (it == db.end()) {
+        pthread_rwlock_unlock(&rwl);
+        return kvssd::kvs_result::KVS_ERR_KS_NOT_EXIST;
+    }
+    db.erase(key);
+    pthread_rwlock_unlock(&rwl);
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+}  // namespace kvssd_hashmap
diff --git a/kvssd/kvssd_hashmap_db.h b/kvssd/kvssd_hashmap_db.h
new file mode 100644
index 00000000..f7e6fd7f
--- /dev/null
+++ b/kvssd/kvssd_hashmap_db.h
@@ -0,0 +1,58 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "kvssd.h"
+#include "kvssd_const.h"
+
+namespace std {
+template <>
+struct hash<kvssd::kvs_key> {
+    size_t operator()(const kvssd::kvs_key &k) const {
+        const uint8_t *data = static_cast<const uint8_t *>(k.key);
+        uint16_t length = k.length;
+
+        size_t hash = 0xcbf29ce484222325;  // FNV-1a init value (64 bits)
+        const size_t fnv_prime = 0x100000001b3;
+
+        for (uint16_t i = 0; i < length; ++i) {
+            hash ^= data[i];    // Byte XOR
+            hash *= fnv_prime;  // FNV-1a Hash Algorithm
+        }
+
+        return hash;
+    }
+};
+}  // namespace std
+
+namespace kvssd_hashmap {
+class Hashmap_KVSSD : public kvssd::KVSSD {
+   public:
+    Hashmap_KVSSD();
+    ~Hashmap_KVSSD();
+
+    kvssd::kvs_result Read(const kvssd::kvs_key &, kvssd::kvs_value &);
+    kvssd::kvs_result Insert(const kvssd::kvs_key &, const kvssd::kvs_value &);
+    kvssd::kvs_result Update(const kvssd::kvs_key &, const kvssd::kvs_value &);
+    kvssd::kvs_result Delete(const kvssd::kvs_key &);
+
+   private:
+    std::unordered_map<kvssd::kvs_key, kvssd::kvs_value> db;
+    pthread_rwlock_t rwl;
+
+    kvssd::kvs_result ValidateRequest(
+        const kvssd::kvs_key &, std::optional<std::reference_wrapper<const kvssd::kvs_value>>);
+    kvssd::kvs_key DeepCopyKey(const kvssd::kvs_key &);
+    kvssd::kvs_value DeepCopyValue(const kvssd::kvs_value &);
+};
+
+}  // namespace kvssd_hashmap
+
+#endif  // YCSB_C_KVSSD_HASHMAP_DB_H_
\ No newline at end of file
diff --git a/kvssd/kvssd_hashmap_db_impl.cc b/kvssd/kvssd_hashmap_db_impl.cc
new file mode 100644
index 00000000..ab3f7df8
--- /dev/null
+++ b/kvssd/kvssd_hashmap_db_impl.cc
@@ -0,0 +1,134 @@
+#include "kvssd_hashmap_db_impl.h"
+
+#include <cstdio>
+#include <iostream>
+
+namespace kvssd_hashmap {
+
+// Field vector to string pointer
+void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data) {
+    for (const ycsbc::DB::Field &field : values) {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+// char* to Field vector pointer
+void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len) {
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim) {
+        assert(p < lim);
+        uint32_t vlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(vlen));
+        p += vlen;
+        uint32_t tlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(tlen));
+        p += tlen;
+        values->push_back({field, value});
+    }
+}
+
+std::unique_ptr<kvs_row, KvsRowDeleter> CreateRow(const std::string &key_in,
+                                                  const std::vector<ycsbc::DB::Field> &value_in) {
+    uint16_t key_length = key_in.size();
+    void *key = malloc(key_length);
+    std::memcpy(key, (void *)(key_in.data()), key_length);
+
+    void *value = nullptr;
+    std::string value_sz;
+    uint32_t value_length = 0;
+    uint32_t actual_value_size = 0;
+    uint32_t offset = 0;
+    if (!value_in.empty()) {
+        SerializeRow(value_in, &value_sz);
+        value = malloc(value_sz.size());
+        std::memcpy(value, value_sz.data(), value_sz.size());
+        value_length = value_sz.size();
+        actual_value_size = value_sz.size();
+        offset = 0;
+    }
+
+    kvssd::kvs_key *newKey = new kvssd::kvs_key;
+    newKey->key = key;
+    newKey->length = key_length;
+    kvssd::kvs_value *newValue = new kvssd::kvs_value;
+    newValue->value = value;
+    newValue->length = value_length;
+    newValue->actual_value_size = actual_value_size;
+    newValue->offset = offset;
+
+    kvs_row *newRow = new kvs_row;
+    newRow->key = newKey;
+    newRow->value = newValue;
+
+    return std::unique_ptr<kvs_row, KvsRowDeleter>(newRow);
+}
+
+// Print kvs_value
+void PrintRow(const kvssd::kvs_value &value) {
+    std::vector<ycsbc::DB::Field> value_vec;
+    DeserializeRow(&value_vec, static_cast<char *>(value.value), value.length);
+    if (value_vec.size() == 0) {
+        printf("The value has empty field.\n");
+        return;
+    }
+    printf("Name: Value\n");
+    for (auto const &field : value_vec) {
+        printf("%s: %s\n", field.name.data(), field.value.data());
+    }
+}
+
+// Print Field vector value
+void PrintFieldVector(const std::vector<ycsbc::DB::Field> &value) {
+    printf("\n");
+    if (value.size() == 0) {
+        printf("The value has empty field.\n");
+        return;
+    }
+    printf("Name: Value\n");
+    for (auto const &field : value) {
+        printf("%s: %s\n", field.name.data(), field.value.data());
+    }
+    printf("\n");
+}
+
+void CheckAPI(const kvssd::kvs_result ret) {
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        throw ycsbc::utils::Exception(std::string(kvssd::kvstrerror[static_cast<int>(ret)]));
+    }
+}
+
+// Wrapper Funtions
+void ReadRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+             std::vector<ycsbc::DB::Field> &value) {
+    value = {};
+    std::unique_ptr<kvs_row, KvsRowDeleter> newRow = CreateRow(key, {});
+    CheckAPI(kvssd->Read(*newRow->key, *newRow->value));
+    DeserializeRow(&value, static_cast<char *>(newRow->value->value), newRow->value->length);
+}
+
+void InsertRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+               const std::vector<ycsbc::DB::Field> &value) {
+    std::unique_ptr<kvs_row, KvsRowDeleter> newRow = CreateRow(key, value);
+    CheckAPI(kvssd->Insert(*newRow->key, *newRow->value));
+}
+
+void UpdateRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+               const std::vector<ycsbc::DB::Field> &value) {
+    std::unique_ptr<kvs_row, KvsRowDeleter> newRow = CreateRow(key, value);
+    CheckAPI(kvssd->Update(*newRow->key, *newRow->value));
+}
+
+void DeleteRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key) {
+    std::unique_ptr<kvs_row, KvsRowDeleter> newRow = CreateRow(key, {});
+    CheckAPI(kvssd->Delete(*newRow->key));
+}
+
+}  // namespace kvssd_hashmap
diff --git a/kvssd/kvssd_hashmap_db_impl.h b/kvssd/kvssd_hashmap_db_impl.h
new file mode 100644
index 00000000..b4366a76
--- /dev/null
+++ b/kvssd/kvssd_hashmap_db_impl.h
@@ -0,0 +1,60 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_IMPL_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_IMPL_H_
+
+#include <atomic>
+#include <memory>
+
+#include "core/db.h"
+#include "kvssd_hashmap_db.h"
+#include "utils/utils.h"
+
+namespace kvssd_hashmap {
+
+struct kvs_row {
+    kvssd::kvs_key *key;
+    kvssd::kvs_value *value;
+};
+
+struct KvsRowDeleter {
+    void operator()(kvs_row *row) const {
+        if (row) {
+            if (row->key) {
+                if (row->key->key) {
+                    free(row->key->key);
+                }
+                delete row->key;
+            }
+            if (row->value) {
+                if (row->value->value) {
+                    free(row->value->value);
+                }
+                delete row->value;
+            }
+            delete row;
+        }
+    }
+};
+
+void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data);
+void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len);
+
+std::unique_ptr<kvs_row, KvsRowDeleter> CreateRow(const std::string &key_in,
+                                                  const std::vector<ycsbc::DB::Field> &value_in);
+
+void PrintRow(const kvssd::kvs_value &value);
+void PrintFieldVector(const std::vector<ycsbc::DB::Field> &value);
+
+void CheckAPI(const kvssd::kvs_result ret);
+
+// Wrapper Functions
+void ReadRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+             std::vector<ycsbc::DB::Field> &value);
+void InsertRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+               const std::vector<ycsbc::DB::Field> &value);
+void UpdateRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key,
+               const std::vector<ycsbc::DB::Field> &value);
+void DeleteRow(const std::unique_ptr<kvssd::KVSSD> &kvssd, const std::string &key);
+
+}  // namespace kvssd_hashmap
+
+#endif  // YCSB_C_KVSSD_HASHMAP_DB_IMPL_H_
\ No newline at end of file
diff --git a/kvssd/test/kvssd_test.cc b/kvssd/test/kvssd_test.cc
new file mode 100644
index 00000000..098c1bb0
--- /dev/null
+++ b/kvssd/test/kvssd_test.cc
@@ -0,0 +1,274 @@
+#include <ctime>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "kvssd_hashmap_db_impl.h"
+
+#define NUM_KEYS 100'000
+#define NUM_VALUES 100'000
+
+namespace {
+class KvssdHashMapDbImplTest : public ::testing::Test {
+   protected:
+    void SetUp() override { kvssd.reset(new kvssd_hashmap::Hashmap_KVSSD()); }
+
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+    std::vector<ycsbc::DB::Field> output_value;
+};
+
+std::string RandomPrintStr(size_t length) {
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i) {
+        randomString += ycsbc::utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = [] {
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<ycsbc::DB::Field>> value = [] {
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<ycsbc::DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++) {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+bool FieldVectorCmp(const std::vector<ycsbc::DB::Field> &value1,
+                    const std::vector<ycsbc::DB::Field> &value2) {
+    if (value1.size() != value2.size()) {
+        return true;
+    }
+    for (size_t i = 0; i < value1.size(); i++) {
+        if (value1[i].name != value2[i].name || value1[i].value != value2[i].value) {
+            return true;
+        }
+    }
+    return false;
+}
+
+struct ThreadArgs {
+    const std::unique_ptr<kvssd::KVSSD> *kv;
+    const std::vector<std::string> *keys;
+    const std::vector<std::vector<ycsbc::DB::Field>> *values;
+    size_t start_idx;
+    size_t end_idx;
+    bool success;
+    std::string error_msg;
+};
+
+void *ParallelInsertUpdateRead(void *arg) {
+    ThreadArgs *args = static_cast<ThreadArgs *>(arg);
+    auto &kv_ref = *(args->kv);
+    auto &ks = *(args->keys);
+    auto &vals = *(args->values);
+    args->success = true;
+
+    try {
+        // Insert
+        for (size_t i = args->start_idx; i < args->end_idx; i++) {
+            kvssd_hashmap::InsertRow(kv_ref, ks[i], vals[i]);
+        }
+
+        // Update
+        size_t range = args->end_idx - args->start_idx;
+        for (size_t i = args->start_idx; i < args->end_idx; i++) {
+            size_t update_idx = args->start_idx + ((i - args->start_idx + 100) % range);
+            kvssd_hashmap::UpdateRow(kv_ref, ks[i], vals[update_idx]);
+        }
+
+        // Read & Check
+        std::vector<ycsbc::DB::Field> output_val;
+        for (size_t i = args->start_idx; i < args->end_idx; i++) {
+            size_t check_idx = args->start_idx + ((i - args->start_idx + 100) % range);
+            kvssd_hashmap::ReadRow(kv_ref, ks[i], output_val);
+
+            if (FieldVectorCmp(output_val, vals[check_idx])) {
+                args->success = false;
+                args->error_msg = "Data mismatch for key: " + ks[i];
+                return nullptr;
+            }
+        }
+    } catch (const ycsbc::utils::Exception &e) {
+        args->success = false;
+        args->error_msg = std::string("Caught ycsbc::utils::Exception: ") + e.what();
+    } catch (const std::exception &e) {
+        args->success = false;
+        args->error_msg = std::string("Caught std::exception: ") + e.what();
+    } catch (...) {
+        args->success = false;
+        args->error_msg = "Caught unknown exception";
+    }
+
+    return nullptr;
+}
+
+TEST_F(KvssdHashMapDbImplTest, ReadSmall) {
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[i], output_value));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, ReadLarge) {
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[i], output_value));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, Reinsertion) {
+    EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[0], value[0]));
+    EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[1], value[1]));
+    EXPECT_THROW(
+        {
+            try {
+                kvssd_hashmap::InsertRow(kvssd, key[0], value[2]);
+            } catch (const ycsbc::utils::Exception &e) {
+                EXPECT_STREQ("Key space is already created", e.what());
+                throw;
+            }
+        },
+        ycsbc::utils::Exception);
+    EXPECT_THROW(
+        {
+            try {
+                kvssd_hashmap::InsertRow(kvssd, key[1], value[3]);
+            } catch (const ycsbc::utils::Exception &e) {
+                EXPECT_STREQ("Key space is already created", e.what());
+                throw;
+            }
+        },
+        ycsbc::utils::Exception);
+}
+
+TEST_F(KvssdHashMapDbImplTest, UpdateSmall) {
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::UpdateRow(kvssd, key[i], value[i + 10]));
+    }
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[i + 10], output_value));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, UpdateLarge) {
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::UpdateRow(kvssd, key[i], value[(i + 500) % NUM_KEYS]));
+    }
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[(i + 500) % NUM_KEYS], output_value));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, UpdateAccessInvalidKey) {
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    EXPECT_THROW(
+        {
+            try {
+                kvssd_hashmap::UpdateRow(kvssd, key[99], value[99]);
+            } catch (const ycsbc::utils::Exception &e) {
+                EXPECT_STREQ("Key space does not exist", e.what());
+                throw;
+            }
+        },
+        ycsbc::utils::Exception);
+}
+
+TEST_F(KvssdHashMapDbImplTest, DeleteSmall) {
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[i], output_value));
+        EXPECT_NO_THROW(kvssd_hashmap::DeleteRow(kvssd, key[i]));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, DeleteLarge) {
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    for (size_t i = 0; i < NUM_KEYS; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::ReadRow(kvssd, key[i], output_value));
+        EXPECT_FALSE(FieldVectorCmp(value[i], output_value));
+        EXPECT_NO_THROW(kvssd_hashmap::DeleteRow(kvssd, key[i]));
+    }
+}
+
+TEST_F(KvssdHashMapDbImplTest, DeleteAccessInvalidKey) {
+    for (size_t i = 0; i < 10; i++) {
+        EXPECT_NO_THROW(kvssd_hashmap::InsertRow(kvssd, key[i], value[i]));
+    }
+    EXPECT_THROW(
+        {
+            try {
+                kvssd_hashmap::DeleteRow(kvssd, key[99]);
+            } catch (const ycsbc::utils::Exception &e) {
+                EXPECT_STREQ("Key space does not exist", e.what());
+                throw;
+            }
+        },
+        ycsbc::utils::Exception);
+}
+
+TEST_F(KvssdHashMapDbImplTest, ParallelOperations) {
+    const size_t NUM_THREADS = 4;
+    pthread_t threads[NUM_THREADS];
+    ThreadArgs thread_args[NUM_THREADS];
+
+    size_t range_per_thread = NUM_KEYS / NUM_THREADS;
+
+    for (size_t t = 0; t < NUM_THREADS; t++) {
+        thread_args[t].kv = &kvssd;
+        thread_args[t].keys = &key;
+        thread_args[t].values = &value;
+        thread_args[t].start_idx = t * range_per_thread;
+        thread_args[t].end_idx = (t == NUM_THREADS - 1) ? NUM_KEYS : (t + 1) * range_per_thread;
+        thread_args[t].success = false;
+        thread_args[t].error_msg = "";
+    }
+
+    for (size_t t = 0; t < NUM_THREADS; t++) {
+        int ret = pthread_create(&threads[t], nullptr, ParallelInsertUpdateRead, &thread_args[t]);
+        ASSERT_EQ(ret, 0) << "pthread_create failed on thread " << t;
+    }
+
+    for (size_t t = 0; t < NUM_THREADS; t++) {
+        int ret = pthread_join(threads[t], nullptr);
+        ASSERT_EQ(ret, 0) << "pthread_join failed on thread " << t;
+    }
+
+    for (size_t t = 0; t < NUM_THREADS; t++) {
+        EXPECT_TRUE(thread_args[t].success)
+            << "Thread " << t << " operations failed. Error: " << thread_args[t].error_msg;
+    }
+}
+}  // anonymous namespace
\ No newline at end of file


Reviews:
user: login: BlaCkinkGJ
body: 전반적으로 어려우실텐데도 불구하고 훌륭하게 해주셔서 감사합니다. 🙇 몇 가지 사항들에 대해서 리뷰를 남겼습니다. 해당 부분들 확인되면 바로 LGTM 드릴 수 있도록 하겠습니다. 🙂 
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T17:49:32Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:08Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:13Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:20Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:37Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:41Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:39:43Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:40:24Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:40:56Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:41:17Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:41:43Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:41:46Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:41:55Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:42:02Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T20:42:24Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:07:06Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:16:41Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:17:19Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:38:02Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:40:29Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-01T21:57:17Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T09:03:35Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T12:42:49Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T12:51:19Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T12:51:52Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T12:54:23Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T13:05:31Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T13:16:45Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T13:17:00Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T13:18:27Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:14:45Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:14:49Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:30:06Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:31:18Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:40:51Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:42:22Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:49:52Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:51:54Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:52:04Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:54:06Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:55:28Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:55:44Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:56:11Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-02T14:57:01Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-04T13:34:05Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-04T13:34:47Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-04T13:36:05Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-04T13:36:37Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-04T13:36:59Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T06:32:00Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T06:35:49Z
user: login: BlaCkinkGJ
body: main 브랜치에서 pull을 받아서 업데이트 하는 것이 좋을 것 같아요. :) 그리고 추가로 생각나서 올립니다 ㅠㅠㅠ 일전에 리뷰할 때 한꺼번에 해드려야했는데 미처놓쳤네요.....
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T13:01:18Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T13:09:59Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T13:14:31Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T14:06:00Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T14:08:17Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-05T14:18:42Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T04:37:11Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T04:38:36Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T05:30:22Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T06:03:44Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T13:32:33Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T14:02:20Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T14:16:54Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T14:19:51Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T14:30:30Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T15:09:30Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T15:10:24Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:31:55Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:32:10Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:34:23Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:46:54Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:48:11Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-06T19:48:54Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T14:56:55Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:00:02Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:02:34Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:02:48Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:07:04Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:09:58Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-16T15:18:52Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-17T15:40:14Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-17T15:41:02Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-17T16:15:11Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-17T16:16:45Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-17T17:29:19Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T03:33:57Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T13:22:49Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T13:26:37Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T13:28:54Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T13:30:46Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T14:31:41Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T14:32:46Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-18T14:34:04Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-26T11:41:15Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2024-12-26T11:46:43Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-01-15T12:21:23Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-01-15T12:27:26Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-01-15T12:27:59Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-01-15T12:31:59Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-04T17:44:46Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-04T17:45:09Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-04T17:45:24Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-04T17:48:03Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-29T11:21:19Z
user: login: BlaCkinkGJ
body: 전반적으로 LGTM입니다! 약간의 커멘트만 처리해주시면 바로 approve 날리고 가겠습니다.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T00:36:34Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:51:23Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:51:33Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:51:55Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:51:59Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:52:02Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:52:05Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T02:52:08Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T03:03:25Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T03:21:30Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T03:22:30Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T03:23:20Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T03:53:26Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T04:05:18Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T04:57:32Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T04:58:34Z
user: login: BlaCkinkGJ
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T05:02:08Z
user: login: BlaCkinkGJ
body: LGTM 👍 고생 많으셨습니다!!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-27T05:02:36Z
user: login: easter423
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-27T05:04:07Z

Review comments:
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+    find_package(kvssd CONFIG)
+    if(kvssd_FOUND)
+        target_link_libraries(ycsb PRIVATE kvssd)
+    else()
+        message(STATUS "Try to find kvssd library using find_library")
+        find_library(KVSSD_LIB kvssd REQUIRED)
+        find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+        target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+        target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+    endif()
+    message(STATUS "Found KVSSD library")
+else()
+    message(STATUS "BIND_KVSSD - OFF")
path: CMakeLists.txt
user: login: BlaCkinkGJ
body: 현재는 라이브러리가 저희가 준비된 것이 없기 때문에 없어도 될 부분으로 보입니다.
created_at: 2024-12-01T17:13:03Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+	LDFLAGS += -lkvssd
path: Makefile
user: login: BlaCkinkGJ
body: KVSSD 라이브러리가 없기 때문에 이 부분은 필요 없을 것 같습니다.
created_at: 2024-12-01T17:13:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
+
+#include <kvssd.h>
+
+const char *kvstrerror[] = {
+    "Successful",                           // KVS_SUCCESS
+    "Buffer space is not enough",           // KVS_ERR_BUFFER_SMALL
+    "Device does not have enough space",    // KVS_ERR_DEV_CAPAPCITY
+    "No device with the dev_hd exists",     // KVS_ERR_DEV_NOT_EXIST
+    "Key space does not have enough space", // KVS_ERR_KS_CAPACITY
+    "Key space is already created",         // KVS_ERR_KS_EXIST
+    "Index is not valid",                   // KVS_ERR_KS_INDEX
+    "Key space name is not valid",          // KVS_ERR_KS_NAME
+    "Key space does not exist",             // KVS_ERR_KS_NOT_EXIST
+    "Key space does not open",              // KVS_ERR_KS_NOT_OPEN
+    "Key space is already opened",          // KVS_ERR_KS_OPEN
+    "Iterator filter is not valid",         // KVS_ERR_ITERATOR_FILTER_INVALID
+    "Maximum number of iterators opened",   // KVS_ERR_ITERATOR_MAX
+    "Iterator Key Group does not exist",    // KVS_ERR_ITERATOR_NOT_EXIST
+    "Iterator is already opened",           // KVS_ERR_ITERATOR_OPEN
+    "Key is not valid",                     // KVS_ERR_KEY_LENGTH_INVALID
+    "Key does not exist",                   // KVS_ERR_KEY_NOT_EXIST
+    "Option is not supported",              // KVS_ERR_OPTION_INVALID
+    "Null input parameter",                 // KVS_ERR_PARAM_INVALID
+    "I/O error occurs",                     // KVS_ERR_SYS_IO
+    "Value length is out of range",         // KVS_ERR_VALUE_LENGTH_INVALID
+    "Value offset is out of range",         // KVS_ERR_VALUE_OFFSET_INVALID
+    "Value offset is misaligned",           // KVS_ERR_VALUE_OFFSET_MISALIGNED
+    "Value update is not allowed",          // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+    "Device was not opened yet"             // KVS_ERR_DEV_NOT_OPENED
+};
+
+Hashmap_KVSSD::Hashmap_KVSSD()
+{
+    // initialize
+}
+Hashmap_KVSSD::~Hashmap_KVSSD()
+{
+    // cleanup
+}
+
+/** @todo
+ * @brief Read API 함수
+ * @param[in] key 찾을 row의 key
+ * @param[out] value_out 찾은 row의 value
+ * @return kvs_result
+ */
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: 우리가 외부에 제공하는 일종의 라이브러리나 API 솔루션이 아니라면 주석은 오히려 코드 가독성을 낮추는 측면이 있습니다. 혹시 그럼에도 불구하고 Doxygen을 사용해야 하는 이유가 있으려나요? 🤔 
created_at: 2024-12-01T17:16:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: include도 convention을 맞춰주셨으면 합니다!

https://stackoverflow.com/questions/691079/is-there-a-standard-include-convention-for-c
created_at: 2024-12-01T17:18:22Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: `core/db.h`의 Field를 사용하지 않는 이유가 있을까요?
created_at: 2024-12-01T17:20:36Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
+
+/**
+ * @brief DB row의 key struct type
+ */
+struct kvs_key
+{
+    void *key;
+    uint16_t length;
+
+    ~kvs_key()
+    {
+        delete[] static_cast<char *>(key);
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: void 포인터에 delete[]가 작동을 하던가요? new로 배열을 할당했다면 모르겠지만 그렇지 않은 경우에는 크기를 모르기 때문에 Memory Leakage가 발생할 것 같습니다. Valgrind 같은 툴을 통해서 메모리 누수 여부 확인이 필요할 것 같습니다.
created_at: 2024-12-01T17:24:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
+
+/**
+ * @brief DB row의 key struct type
+ */
+struct kvs_key
+{
+    void *key;
+    uint16_t length;
+
+    ~kvs_key()
+    {
+        delete[] static_cast<char *>(key);
+    }
+
+    bool operator==(const kvs_key &other) const
+    {
+        return length == other.length &&
+               std::memcmp(key, other.key, length) == 0;
+    }
+};
+
+template <>
+struct std::hash<kvs_key>
+{
+    std::size_t operator()(const kvs_key &k) const
+    {
+        const uint8_t *data = static_cast<const uint8_t *>(k.key); // 바이트 단위로 접근
+        uint16_t length = k.length;
+
+        std::size_t hash = 0xcbf29ce484222325; // FNV-1a 초기값 (64비트)
+        const std::size_t fnv_prime = 0x100000001b3;
+
+        for (uint16_t i = 0; i < length; ++i)
+        {
+            hash ^= data[i];   // 바이트를 XOR 연산
+            hash *= fnv_prime; // FNV-1a 해시 알고리즘의 주요 곱셈 단계
+        }
+
+        return hash;
+    }
+};
+
+/**
+ * @brief DB row의 value struct type
+ */
+struct kvs_value
+{
+    void *value;                // value byte stream 버퍼의 시작 주소
+    uint32_t length;            // value byte stream 버퍼의 크기 (단위: byte)
+    uint32_t actual_value_size; // device에 저장된 value의 실제 크기 (단위: byte)
+    uint32_t offset;            // [optional] device에 저장된 value의 offset (단위: byte)
+
+    ~kvs_value()
+    {
+        delete[] static_cast<char *>(value);
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: 위에서 언급되었 듯이 메모리 이슈가 우려됩니다.
created_at: 2024-12-01T17:29:42Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 이거 어떤 함수 때문에 사용하게 된 것일까요?

보통 사용을 권고하지 않습니다.
https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h
created_at: 2024-12-01T17:31:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 불필요한 커멘트가 코드에 남아있어서는 안됩니다.
created_at: 2024-12-01T17:34:01Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 절대로 구조체에 바로 넣지 않으시길 바랍니다. 구조체의 멤버 값은 모든 값이 정상일 때 넣기를 권고드립니다. Exception 상황에서 멤버 값이 갱신되면 안됨에도 불구하고 갱신이 되는 불상사가 벌어질 수 있습니다. 
created_at: 2024-12-01T17:36:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: ```suggestion
    void *key = static_cast<void *>(key_data);
    size_t key_length = key_in.size();
```
created_at: 2024-12-01T17:36:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 이 이후에 value도 동일한 처리를 해 준 다음에 각 값을 바탕으로 kvs_key, kvs_value 구조체를 만들어서 각 멤버에 초기화와 동시에 할당하는 방식이 좋좋을 것 같습니다.
created_at: 2024-12-01T17:39:57Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: key_in.size()가 정상인지를 확인할 필요가 있을 것 같습니다.
created_at: 2024-12-01T17:42:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: length에 대한 OpenMPDK의 KV API에서 뭔가 제약사항이 있을 느낌이네요. (보통 4KiB 단위로 내려야 한다거나 이런 제약이 있습니다.) 이점 유념을 해보면 좋을 것 같습니다. 
created_at: 2024-12-01T17:44:06Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: kvssd_hashmap_db_run 보다는 kvssd_hashmap_db_impl이 좋을 것 같습니다. 그리고 test 부분은 따로 ctest나 gtest 같은 것을 참고해서 따로 빼는 것이 좋습니다. 
created_at: 2024-12-01T17:46:03Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: BlaCkinkGJ
body: 이건 뭔가요?
created_at: 2024-12-01T17:46:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
+
+    return newRow;
+}
+
+class Exception : public std::exception
+{
+public:
+    Exception(const std::string &message) : message_(message) {}
+    const char *what() const noexcept
+    {
+        return message_.c_str();
+    }
+
+private:
+    std::string message_;
+};
+
+/**
+ * @brief kvssd API 함수의 반환값을 보고 에러 여부를 확인하는 함수
+ *
+ * 에러가 발생한 경우 에러 문구를 출력한 뒤 프로그램을 종료한다.
+ * @param[in] ret kvssd API 함수의 반환값
+ */
+void CheckAPI(kvs_result ret)
+{
+    if (ret != KVS_SUCCESS)
+    {
+        // printf("kvssd error (errmsg: %s)\n", kvstrerror[ret]);
+        throw Exception(std::string(kvstrerror[ret]));
+    }
+    printf("%s\n", kvstrerror[ret]);
+}
+
+int main(void)
+{
+    printf("[Debug] Test started\n");
+
+    std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+    std::string key1 = "key1";
+    std::string key2 = "key2";
+    std::vector<Field> value1 = {{"field1", "value1_1"}, {"field2", "value1_2"}};
+    std::vector<Field> value2 = {{"field1", "value2_1"}, {"field2", "value2_2"}};
+    std::unique_ptr<kvs_row> row1 = CreateRow(key1, value1);
+    std::unique_ptr<kvs_row> row2 = CreateRow(key2, value2);
+
+    CheckAPI(kvssd->Insert(*row1->key, *row1->value));
+    CheckAPI(kvssd->Read(*row1->key, *row1->value));
+    CheckAPI(kvssd->Update(*row1->key, *row1->value));
+    CheckAPI(kvssd->Delete(*row1->key));
+
+    printf("[Debug] Test ended\n");
+    return 0;
+}
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 테스트는 Expected가 있고 이를 Actual가 비교하는 방식으로 진행되어야 합니다. API의 성공 동작 여부만 확인하는 방식은 너무 naive한 느낌이 있습니다.
created_at: 2024-12-01T17:48:09Z
author_association: COLLABORATOR
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+    find_package(kvssd CONFIG)
+    if(kvssd_FOUND)
+        target_link_libraries(ycsb PRIVATE kvssd)
+    else()
+        message(STATUS "Try to find kvssd library using find_library")
+        find_library(KVSSD_LIB kvssd REQUIRED)
+        find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+        target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+        target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+    endif()
+    message(STATUS "Found KVSSD library")
+else()
+    message(STATUS "BIND_KVSSD - OFF")
path: CMakeLists.txt
user: login: easter423
body: 해당 부분(Line 93~103) 주석 처리하였습니다.
created_at: 2024-12-01T20:39:08Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+	LDFLAGS += -lkvssd
path: Makefile
user: login: easter423
body: Line 66 주석 처리 하였습니다.
created_at: 2024-12-01T20:39:13Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
+
+#include <kvssd.h>
+
+const char *kvstrerror[] = {
+    "Successful",                           // KVS_SUCCESS
+    "Buffer space is not enough",           // KVS_ERR_BUFFER_SMALL
+    "Device does not have enough space",    // KVS_ERR_DEV_CAPAPCITY
+    "No device with the dev_hd exists",     // KVS_ERR_DEV_NOT_EXIST
+    "Key space does not have enough space", // KVS_ERR_KS_CAPACITY
+    "Key space is already created",         // KVS_ERR_KS_EXIST
+    "Index is not valid",                   // KVS_ERR_KS_INDEX
+    "Key space name is not valid",          // KVS_ERR_KS_NAME
+    "Key space does not exist",             // KVS_ERR_KS_NOT_EXIST
+    "Key space does not open",              // KVS_ERR_KS_NOT_OPEN
+    "Key space is already opened",          // KVS_ERR_KS_OPEN
+    "Iterator filter is not valid",         // KVS_ERR_ITERATOR_FILTER_INVALID
+    "Maximum number of iterators opened",   // KVS_ERR_ITERATOR_MAX
+    "Iterator Key Group does not exist",    // KVS_ERR_ITERATOR_NOT_EXIST
+    "Iterator is already opened",           // KVS_ERR_ITERATOR_OPEN
+    "Key is not valid",                     // KVS_ERR_KEY_LENGTH_INVALID
+    "Key does not exist",                   // KVS_ERR_KEY_NOT_EXIST
+    "Option is not supported",              // KVS_ERR_OPTION_INVALID
+    "Null input parameter",                 // KVS_ERR_PARAM_INVALID
+    "I/O error occurs",                     // KVS_ERR_SYS_IO
+    "Value length is out of range",         // KVS_ERR_VALUE_LENGTH_INVALID
+    "Value offset is out of range",         // KVS_ERR_VALUE_OFFSET_INVALID
+    "Value offset is misaligned",           // KVS_ERR_VALUE_OFFSET_MISALIGNED
+    "Value update is not allowed",          // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+    "Device was not opened yet"             // KVS_ERR_DEV_NOT_OPENED
+};
+
+Hashmap_KVSSD::Hashmap_KVSSD()
+{
+    // initialize
+}
+Hashmap_KVSSD::~Hashmap_KVSSD()
+{
+    // cleanup
+}
+
+/** @todo
+ * @brief Read API 함수
+ * @param[in] key 찾을 row의 key
+ * @param[out] value_out 찾은 row의 value
+ * @return kvs_result
+ */
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: vscode를 사용하면서 함수에 mouse hover 시 doxygen이 활용되는 기능이 있어서 사용하였지만, 제가 생각해도 가독성이 떨어진 것 같아 필요한 설명 외에는 전부 지우도록 하겠습니다. 🤧
created_at: 2024-12-01T20:39:20Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: core/db.h 내에서도 ycsbc namespace 안의 DB class에 public으로 설정되었던 것이라 따로 빼놓았는데, 사용하는 것이 좋다면 코드 외부를 ycsbc namespace로 감싼 후 DB::Field로 명시하여 사용하겠습니다.

+ [질문] Field가 현재 ```kvssd_hashmap_db_run.cc```에서만 사용되는데, 이외의 다른 두 파일들에 대해서도 모두 ycsbc namespace를 감싸줘야 하는 지 궁금합니다.

+ [질문2] ```using namespace ycsbc``` 구문을 사용해도 되는지 궁금합니다.
created_at: 2024-12-01T20:39:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
+
+/**
+ * @brief DB row의 key struct type
+ */
+struct kvs_key
+{
+    void *key;
+    uint16_t length;
+
+    ~kvs_key()
+    {
+        delete[] static_cast<char *>(key);
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 해당 부분 수정하였습니다. (소멸자 삭제)
created_at: 2024-12-01T20:39:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
+
+/**
+ * @brief DB row의 key struct type
+ */
+struct kvs_key
+{
+    void *key;
+    uint16_t length;
+
+    ~kvs_key()
+    {
+        delete[] static_cast<char *>(key);
+    }
+
+    bool operator==(const kvs_key &other) const
+    {
+        return length == other.length &&
+               std::memcmp(key, other.key, length) == 0;
+    }
+};
+
+template <>
+struct std::hash<kvs_key>
+{
+    std::size_t operator()(const kvs_key &k) const
+    {
+        const uint8_t *data = static_cast<const uint8_t *>(k.key); // 바이트 단위로 접근
+        uint16_t length = k.length;
+
+        std::size_t hash = 0xcbf29ce484222325; // FNV-1a 초기값 (64비트)
+        const std::size_t fnv_prime = 0x100000001b3;
+
+        for (uint16_t i = 0; i < length; ++i)
+        {
+            hash ^= data[i];   // 바이트를 XOR 연산
+            hash *= fnv_prime; // FNV-1a 해시 알고리즘의 주요 곱셈 단계
+        }
+
+        return hash;
+    }
+};
+
+/**
+ * @brief DB row의 value struct type
+ */
+struct kvs_value
+{
+    void *value;                // value byte stream 버퍼의 시작 주소
+    uint32_t length;            // value byte stream 버퍼의 크기 (단위: byte)
+    uint32_t actual_value_size; // device에 저장된 value의 실제 크기 (단위: byte)
+    uint32_t offset;            // [optional] device에 저장된 value의 offset (단위: byte)
+
+    ~kvs_value()
+    {
+        delete[] static_cast<char *>(value);
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 마찬가지로 해당 부분 수정하였습니다. (소멸자 삭제)
created_at: 2024-12-01T20:39:43Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: easter423
body: 기존 [ls4154/ycsb-cpp](https://github.com/ls4154/YCSB-cpp) repo에서 변경된 내용인 것으로 보입니다.
created_at: 2024-12-01T20:40:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
+
+    return newRow;
+}
+
+class Exception : public std::exception
+{
+public:
+    Exception(const std::string &message) : message_(message) {}
+    const char *what() const noexcept
+    {
+        return message_.c_str();
+    }
+
+private:
+    std::string message_;
+};
+
+/**
+ * @brief kvssd API 함수의 반환값을 보고 에러 여부를 확인하는 함수
+ *
+ * 에러가 발생한 경우 에러 문구를 출력한 뒤 프로그램을 종료한다.
+ * @param[in] ret kvssd API 함수의 반환값
+ */
+void CheckAPI(kvs_result ret)
+{
+    if (ret != KVS_SUCCESS)
+    {
+        // printf("kvssd error (errmsg: %s)\n", kvstrerror[ret]);
+        throw Exception(std::string(kvstrerror[ret]));
+    }
+    printf("%s\n", kvstrerror[ret]);
+}
+
+int main(void)
+{
+    printf("[Debug] Test started\n");
+
+    std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+    std::string key1 = "key1";
+    std::string key2 = "key2";
+    std::vector<Field> value1 = {{"field1", "value1_1"}, {"field2", "value1_2"}};
+    std::vector<Field> value2 = {{"field1", "value2_1"}, {"field2", "value2_2"}};
+    std::unique_ptr<kvs_row> row1 = CreateRow(key1, value1);
+    std::unique_ptr<kvs_row> row2 = CreateRow(key2, value2);
+
+    CheckAPI(kvssd->Insert(*row1->key, *row1->value));
+    CheckAPI(kvssd->Read(*row1->key, *row1->value));
+    CheckAPI(kvssd->Update(*row1->key, *row1->value));
+    CheckAPI(kvssd->Delete(*row1->key));
+
+    printf("[Debug] Test ended\n");
+    return 0;
+}
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 각 함수의 Actual Behavior를 확인하는 방식으로 테스트 방식을 보완하였습니다.
e.g. Insert 이후 Read 시 해당 key에 대응되는 value가 읽히는지, Update 이후 Read 시 변경되었는지 등
테스트 파일로 분리 작업도 진행하겠습니다.
created_at: 2024-12-01T20:40:56Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: - 파일명 변경 부분에 한하여 commit을 따로 진행하였습니다.
- 기존에는 ```kvssd_hashmap_db_run.cc``` 파일을 test 용도로 작성하려고 했는데, 구현 부분이 이렇게 방대해질 줄 몰랐습니다. 테스트 부분은 ctest, gtest 참고하여 따로 분리하였습니다. 

- [질문] 자체 제작한 test 파일로도 hashmap-kvssd 검증이 완료된 이후에는 YCSB-cpp에서 제공하는 workload를 돌릴 수 있도록 연결하는 작업을 진행하는 것인가요?
created_at: 2024-12-01T20:41:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 해당 부분은 OpenMPDK에서 찾아본 뒤 답변 드리도록 하겠습니다.
created_at: 2024-12-01T20:41:43Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 해당 부분 역시 OpenMPDK에서 찾아본 뒤 답변 드리도록 하겠습니다.
created_at: 2024-12-01T20:41:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 혹여 field_count_가 필요할까 해서 남겨 놓았었는데, 삭제하였습니다.
created_at: 2024-12-01T20:41:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: kvssd_hashmap_db_run.cc 파일의 경우 수정 및 변경할 부분이 워낙 많다 보니 임시로 추가해 놓았던 것이 아직도 남았었습니다.😅 수정하겠습니다.
created_at: 2024-12-01T20:42:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: 링크 참고하여 수정하겠습니다!
created_at: 2024-12-01T20:42:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: [질문] 약간 다른 주제이지만 mutex의 경우 KVSSD_Hashmap 클래스의 생성자와 소멸자에 적용시킬 예정이었는데, 두 곳 모두 별다른 코드를 넣을 필요성을 찾지 못해서 이 경우 mutex lock은 사용하지 않아도 될까요?
created_at: 2024-12-01T21:07:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 현재 해당 부분은 삭제 후 ```core/db.h``` include하여 사용 중입니다.
created_at: 2024-12-01T21:16:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: include convention 작업과 함께 수정 완료하였습니다.
created_at: 2024-12-01T21:17:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 그렇군요...😮 숙지하였습니다.
created_at: 2024-12-01T21:38:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 말씀해주신 내용대로 임시 변수에 값 할당 => 구조체에 변수에 저장된 값 입력 순으로 변경 완료하였습니다.
created_at: 2024-12-01T21:40:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
+
+/**
+ * @brief DB row의 key struct type
+ */
+struct kvs_key
+{
+    void *key;
+    uint16_t length;
+
+    ~kvs_key()
+    {
+        delete[] static_cast<char *>(key);
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 현재까지 수정한 코드를 4가지 API 함수를 모두 작동시키는 test 환경에서 Valgrind를 통해 확인된 바로는 메모리 누수가 발생하지 않았습니다.

![image](https://github.com/user-attachments/assets/89ce78fa-8c27-43cc-a478-0c579551d70a)
이후로도 코드 업데이트 할 때마다 수시로 확인하겠습니다.
created_at: 2024-12-01T21:57:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
+
+    return newRow;
+}
+
+class Exception : public std::exception
+{
+public:
+    Exception(const std::string &message) : message_(message) {}
+    const char *what() const noexcept
+    {
+        return message_.c_str();
+    }
+
+private:
+    std::string message_;
+};
+
+/**
+ * @brief kvssd API 함수의 반환값을 보고 에러 여부를 확인하는 함수
+ *
+ * 에러가 발생한 경우 에러 문구를 출력한 뒤 프로그램을 종료한다.
+ * @param[in] ret kvssd API 함수의 반환값
+ */
+void CheckAPI(kvs_result ret)
+{
+    if (ret != KVS_SUCCESS)
+    {
+        // printf("kvssd error (errmsg: %s)\n", kvstrerror[ret]);
+        throw Exception(std::string(kvstrerror[ret]));
+    }
+    printf("%s\n", kvstrerror[ret]);
+}
+
+int main(void)
+{
+    printf("[Debug] Test started\n");
+
+    std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+    std::string key1 = "key1";
+    std::string key2 = "key2";
+    std::vector<Field> value1 = {{"field1", "value1_1"}, {"field2", "value1_2"}};
+    std::vector<Field> value2 = {{"field1", "value2_1"}, {"field2", "value2_2"}};
+    std::unique_ptr<kvs_row> row1 = CreateRow(key1, value1);
+    std::unique_ptr<kvs_row> row2 = CreateRow(key2, value2);
+
+    CheckAPI(kvssd->Insert(*row1->key, *row1->value));
+    CheckAPI(kvssd->Read(*row1->key, *row1->value));
+    CheckAPI(kvssd->Update(*row1->key, *row1->value));
+    CheckAPI(kvssd->Delete(*row1->key));
+
+    printf("[Debug] Test ended\n");
+    return 0;
+}
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: **ctest, gtest** 사용하여 테스트 환경을 세팅하였습니다.
- kvssd 디렉터리에 test를 위한 `CMakeList.txt` 파일 생성
- `kvssd/test` 디렉터리에 `kvssd_test.cc` 파일 생성
- `kvssd/build` 디렉터리에서 `cmake ..` 후 `make` 진행 시 테스트 파일 `kvssd_test` Generate

현재까지 만든 테스트에서는 예상과 실제 결과 값이 같고, 추후 예외 케이스를 집중적으로 추가 예정입니다.

![image](https://github.com/user-attachments/assets/38887bb3-3c48-4642-b932-a60aa8014b92)

created_at: 2024-12-02T09:03:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: > Field가 현재 kvssd_hashmap_db_run.cc에서만 사용되는데, 이외의 다른 두 파일들에 대해서도 모두 ycsbc namespace를 감싸줘야 하는 지 궁금합니다.

namespace를 전부 묶어주면 좋을 것 같습니다. lmdb_db.cc랑 lmdb_db.h를 보고 똑같이 묶어주도록 하죠.

unnamed(anonymous) namespace에 관련된 정보는 [링크](https://www.learncpp.com/cpp-tutorial/unnamed-and-inline-namespaces/) 참고 부탁드립니다.

> using namespace ycsbc 구문을 사용해도 되는지 궁금합니다.

using은 보통 사용하지 않는 것이 좋습니다. Google의 C++ Style Guide에서도 권고하지 않는 방식입니다.

https://google.github.io/styleguide/cppguide.html#Namespaces

created_at: 2024-12-02T12:42:49Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: > [질문] 자체 제작한 test 파일로도 hashmap-kvssd 검증이 완료된 이후에는 YCSB-cpp에서 제공하는 workload를 돌릴 수 있도록 연결하는 작업을 진행하는 것인가요?

테스트 파일들의 목적은 내가 만든 로직이 버그가 없는지 확인하기 위해서 가장 작은 단위로 테스트하는 것입니다. YCSB-cpp랑은 거리가 먼 작업이에요.

테스팅에 관한 자료 공유드립니다. https://aws.amazon.com/ko/what-is/unit-testing/
created_at: 2024-12-02T12:51:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
+
+    return newRow;
+}
+
+class Exception : public std::exception
+{
+public:
+    Exception(const std::string &message) : message_(message) {}
+    const char *what() const noexcept
+    {
+        return message_.c_str();
+    }
+
+private:
+    std::string message_;
+};
+
+/**
+ * @brief kvssd API 함수의 반환값을 보고 에러 여부를 확인하는 함수
+ *
+ * 에러가 발생한 경우 에러 문구를 출력한 뒤 프로그램을 종료한다.
+ * @param[in] ret kvssd API 함수의 반환값
+ */
+void CheckAPI(kvs_result ret)
+{
+    if (ret != KVS_SUCCESS)
+    {
+        // printf("kvssd error (errmsg: %s)\n", kvstrerror[ret]);
+        throw Exception(std::string(kvstrerror[ret]));
+    }
+    printf("%s\n", kvstrerror[ret]);
+}
+
+int main(void)
+{
+    printf("[Debug] Test started\n");
+
+    std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+    std::string key1 = "key1";
+    std::string key2 = "key2";
+    std::vector<Field> value1 = {{"field1", "value1_1"}, {"field2", "value1_2"}};
+    std::vector<Field> value2 = {{"field1", "value2_1"}, {"field2", "value2_2"}};
+    std::unique_ptr<kvs_row> row1 = CreateRow(key1, value1);
+    std::unique_ptr<kvs_row> row2 = CreateRow(key2, value2);
+
+    CheckAPI(kvssd->Insert(*row1->key, *row1->value));
+    CheckAPI(kvssd->Read(*row1->key, *row1->value));
+    CheckAPI(kvssd->Update(*row1->key, *row1->value));
+    CheckAPI(kvssd->Delete(*row1->key));
+
+    printf("[Debug] Test ended\n");
+    return 0;
+}
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 멋지십니다 👍👍👍👍👍👍👍 
created_at: 2024-12-02T12:51:52Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: BlaCkinkGJ
body: veritross/master에 병합하는 것이기 때문에 veritross/master에서 가져와서 작업을 수행해야 합니다. 이 경우에는 veritross/master를 업데이트하는 PR을 만들어주시는 것을 권고드립니다.
created_at: 2024-12-02T12:54:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: `using namespace`는 지양을 해주시길 바랍니다.
created_at: 2024-12-02T12:56:38Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 이미 cmake에서 include를 했다면 ".."이 없어도 될 것입니다. 만약에 개인 에디터에서 이슈가 발생한다면 아마도 에디터에서 설정을 안 해줘서 그런 거라서 설정해주시면 해결될 것 같습니다.
created_at: 2024-12-02T12:56:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+bool FieldVectorCmp(std::vector<DB::Field> &value1, std::vector<DB::Field> &value2)
+{
+    size_t len1 = value1.size();
+    size_t len2 = value2.size();
+    if (len1 != len2)
+    {
+        return true;
+    }
+    for (size_t i = 0; i < len1; i++)
+    {
+        if (value1[i].name != value2[i].name)
+        {
+            return true;
+        }
+        if (value1[i].value != value2[i].value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------- TEST START ----------------------- //
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 이런 주석은 보통 안 넣는 것을 권고드립니다. IoT쪽은 가끔있기는 한데, 애초에 gtest가 잘 되어있기 때문에 TEST가 나오는 것만 보면 여기서부터 TEST가 시작된다는 것을 알 수 있어서 좀 verbose한 느낌입니다.
created_at: 2024-12-02T12:58:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+bool FieldVectorCmp(std::vector<DB::Field> &value1, std::vector<DB::Field> &value2)
+{
+    size_t len1 = value1.size();
+    size_t len2 = value2.size();
+    if (len1 != len2)
+    {
+        return true;
+    }
+    for (size_t i = 0; i < len1; i++)
+    {
+        if (value1[i].name != value2[i].name)
+        {
+            return true;
+        }
+        if (value1[i].value != value2[i].value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------- TEST START ----------------------- //
+
+TEST(READ, Simple)
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: ```suggestion
TEST(KvssdHashMapDbImplTest, ReadSmall)
```

좀 더 명확하게 테스트 이름을 정해주시면 좋을 것 같습니다.
created_at: 2024-12-02T13:02:09Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 외부 파일에서 참고하지 않는 내용들은 `static` 사용 혹은 `anonymous namespace`로 감싸주시길 바랍니다.
created_at: 2024-12-02T13:03:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+bool FieldVectorCmp(std::vector<DB::Field> &value1, std::vector<DB::Field> &value2)
+{
+    size_t len1 = value1.size();
+    size_t len2 = value2.size();
+    if (len1 != len2)
+    {
+        return true;
+    }
+    for (size_t i = 0; i < len1; i++)
+    {
+        if (value1[i].name != value2[i].name)
+        {
+            return true;
+        }
+        if (value1[i].value != value2[i].value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------- TEST START ----------------------- //
+
+TEST(READ, Simple)
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 이후 TEST들도 함께 수정해주세요.
created_at: 2024-12-02T13:03:31Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+#	LDFLAGS += -lkvssd
path: Makefile
user: login: BlaCkinkGJ
body: 커멘트로 남기지 마시고 반드시 지워주시길 바랍니다. 나중에 필요하면 PR에서 Commit을 바탕으로 추적하면 됩니다.
created_at: 2024-12-02T13:04:45Z
author_association: COLLABORATOR
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+#     find_package(kvssd CONFIG)
+#     if(kvssd_FOUND)
+#         target_link_libraries(ycsb PRIVATE kvssd)
+#     else()
+#         message(STATUS "Try to find kvssd library using find_library")
+#         find_library(KVSSD_LIB kvssd REQUIRED)
+#         find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+#         target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+#         target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+#     endif()
+#     message(STATUS "Found KVSSD library")
path: CMakeLists.txt
user: login: BlaCkinkGJ
body: 불필요한 주석은 남기지 않아주시길 바랍니다. 향후 PR의 Commit을 찾아보는 것을 추천합니다.
created_at: 2024-12-02T13:05:15Z
author_association: COLLABORATOR
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+    find_package(kvssd CONFIG)
+    if(kvssd_FOUND)
+        target_link_libraries(ycsb PRIVATE kvssd)
+    else()
+        message(STATUS "Try to find kvssd library using find_library")
+        find_library(KVSSD_LIB kvssd REQUIRED)
+        find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+        target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+        target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+    endif()
+    message(STATUS "Found KVSSD library")
+else()
+    message(STATUS "BIND_KVSSD - OFF")
path: CMakeLists.txt
user: login: BlaCkinkGJ
body: 주석 처리보다는 삭제를 추천드립니다!
created_at: 2024-12-02T13:16:45Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+	LDFLAGS += -lkvssd
path: Makefile
user: login: BlaCkinkGJ
body: 주석보다는 삭제를 추천드립니다.
created_at: 2024-12-02T13:17:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: 클래스 생성자와 소멸자에 Mutex가 필요할 필요가 있을까요? Mutex는 Critical Section에만 넣어주면 될 것 같습니다!! unordered_map이 thread safe인지 아닌지를 확인하면 좋을 것 같습니다.

https://stackoverflow.com/questions/9685486/unordered-map-thread-safety
created_at: 2024-12-02T13:18:27Z
author_association: COLLABORATOR
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+    find_package(kvssd CONFIG)
+    if(kvssd_FOUND)
+        target_link_libraries(ycsb PRIVATE kvssd)
+    else()
+        message(STATUS "Try to find kvssd library using find_library")
+        find_library(KVSSD_LIB kvssd REQUIRED)
+        find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+        target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+        target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+    endif()
+    message(STATUS "Found KVSSD library")
+else()
+    message(STATUS "BIND_KVSSD - OFF")
path: CMakeLists.txt
user: login: easter423
body: 삭제 완료하였습니다.
created_at: 2024-12-02T14:14:45Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+	LDFLAGS += -lkvssd
path: Makefile
user: login: easter423
body: 삭제 완료하였습니다.
created_at: 2024-12-02T14:14:49Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 그렇군요..! 감사합니다.
created_at: 2024-12-02T14:30:06Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 그렇다면 테스트와 별개로 Hashmap kvssd에 대해서도 YCSB-cpp 벤치마크를 돌리는지 궁금합니다.
created_at: 2024-12-02T14:31:18Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: easter423
body: 분명 veritross/master를 fork하였음에도 해당 부분이 있어 의아하게 생각하고 있었습니다. 😕
관련하여 PR(#6) 만들었습니다.
created_at: 2024-12-02T14:40:51Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: using 구문은 전부 삭제하였습니다.
anonymous namespace 관련하여 lmdb_db.cc에서 사용되는 것으로 보이는데, 해당 코드를 그대로 복사해 놓으면 될까요?
created_at: 2024-12-02T14:42:22Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: unordered_map 자체가 thread-safe가 아니었군요...... 읽고 쓰는 부분에 mutex 추가하곘습니다.
created_at: 2024-12-02T14:49:52Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 에디터 문제가 맞습니다 😥 Cmake test 관련하여 계속 말썽이네요...
관련하여서는 추후에 문제 해결 되면 수정하도록 하겠습니다.
created_at: 2024-12-02T14:51:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 수정하였습니다!
created_at: 2024-12-02T14:52:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+bool FieldVectorCmp(std::vector<DB::Field> &value1, std::vector<DB::Field> &value2)
+{
+    size_t len1 = value1.size();
+    size_t len2 = value2.size();
+    if (len1 != len2)
+    {
+        return true;
+    }
+    for (size_t i = 0; i < len1; i++)
+    {
+        if (value1[i].name != value2[i].name)
+        {
+            return true;
+        }
+        if (value1[i].value != value2[i].value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------- TEST START ----------------------- //
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 삭제하였습니다.
created_at: 2024-12-02T14:54:06Z
author_association: COLLABORATOR
diff_hunk: @@ -61,6 +62,11 @@ ifeq ($(BIND_SQLITE), 1)
 	SOURCES += $(wildcard sqlite/*.cc)
 endif
 
+ifeq ($(BIND_KVSSD), 1)
+#	LDFLAGS += -lkvssd
path: Makefile
user: login: easter423
body: 삭제 완료하였습니다. :)
created_at: 2024-12-02T14:55:28Z
author_association: COLLABORATOR
diff_hunk: @@ -84,6 +85,26 @@ else()
     message(STATUS "BIND_LMDB - OFF")
 endif()
 
+if (BIND_KVSSD)
+    message(STATUS "BIND_KVSSD - ON")
+    file(GLOB_RECURSE YCSB_KVSSD_SRC "kvssd/*.cc")
+    target_sources(ycsb PRIVATE ${YCSB_KVSSD_SRC})
+
+#     find_package(kvssd CONFIG)
+#     if(kvssd_FOUND)
+#         target_link_libraries(ycsb PRIVATE kvssd)
+#     else()
+#         message(STATUS "Try to find kvssd library using find_library")
+#         find_library(KVSSD_LIB kvssd REQUIRED)
+#         find_path(KVSSD_INCLUDE_DIR "kvssd.h" REQUIRED)
+#         target_link_libraries(ycsb PRIVATE ${KVSSD_LIB})
+#         target_include_directories(ycsb PRIVATE ${KVSSD_INCLUDE_DIR})
+#     endif()
+#     message(STATUS "Found KVSSD library")
path: CMakeLists.txt
user: login: easter423
body: 마찬가지로 삭제 완료하였습니다!!
created_at: 2024-12-02T14:55:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: anonymous namespace로 감싸는 방식으로 진행하겠습니다.
created_at: 2024-12-02T14:56:11Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
+
+bool FieldVectorCmp(std::vector<DB::Field> &value1, std::vector<DB::Field> &value2)
+{
+    size_t len1 = value1.size();
+    size_t len2 = value2.size();
+    if (len1 != len2)
+    {
+        return true;
+    }
+    for (size_t i = 0; i < len1; i++)
+    {
+        if (value1[i].name != value2[i].name)
+        {
+            return true;
+        }
+        if (value1[i].value != value2[i].value)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------- TEST START ----------------------- //
+
+TEST(READ, Simple)
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 명시된 내용처럼 수정하겠습니다.
created_at: 2024-12-02T14:57:01Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: Mutex 보다는 RWLock을 사용하는 것을 추천해요!!

https://github.com/tsixta/tsmap/blob/master/tsmap.h
created_at: 2024-12-04T13:34:05Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: 그대로 복사하는 것보다는 참고해서 개선하는 것이라고 하는 것이 좋을 것 같아요.
created_at: 2024-12-04T13:34:47Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: 넵, 당연합니다. 단위 테스트랑 달리 통합 테스트도 놓쳐서는 안되죠.
created_at: 2024-12-04T13:36:05Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: BlaCkinkGJ
body: 아마 fork 이후에 업데이트 된 내용이라서 그럴겁니다. 해당 PR approve 했습니다!
created_at: 2024-12-04T13:36:37Z
author_association: COLLABORATOR
diff_hunk: @@ -225,7 +225,7 @@ void RocksdbDB::Cleanup() {
   }
   for (size_t i = 0; i < cf_handles_.size(); i++) {
     if (cf_handles_[i] != nullptr) {
-      delete cf_handles_[i];
+      db_->DestroyColumnFamilyHandle(cf_handles_[i]);
path: rocksdb/rocksdb_db.cc
user: login: BlaCkinkGJ
body: PR 링크만 이슈에 해주시길 바래요~
created_at: 2024-12-04T13:36:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: OpenMPDK 내 [PDK/core/src/api/include/private/kvs_utils.h](https://github.com/snu-csl/KVSSD_5.10.37/blob/82cf1e1ecba8bcec256177de2b80d9c9fde87ad4/PDK/core/src/api/include/private/kvs_utils.h#L262)에서 key와 value에 대해 올바른지 check하는 부분을 찾았습니다.
더 자세한 내용은 [노션](https://www.notion.so/121d07017c0f806abbf5ce337fe302d8?v=121d07017c0f812fa97e000cc005fbaf&p=f678c179ad2b4aaebd0acd23a9887cea&pm=s)에 정리하였습니다.

- validate_request() 함수는 각 KV API 함수가 호출되고 바로 실행되며, 해당 함수는 validate_kv_pair_()를 다시 호출합니다. 해당 함수의 매개변수는 순서대로 check할 kvs_key pointer, kvs_value pointer, max_value_len(uint32_t)입니다.
- kvs_key 포인터가 NULL이 아니라면, 다음 사항을 모두 체크합니다.
    - 해당 포인터가 가리키는 struct 내의 length에 대해 MIN, MAX 길이를 확인합니다. OpenMPDK 내에서 **허용된 key의 길이는 4 이상 255 이하**입니다. 이 조건에 맞지 않다면 KVS_ERR_KEY_LENGTH_INVALID 에러를 반환합니다.
    - 해당 포인터가 가리키는 struct 내의 key(buffer) 포인터에 대해 NULL 여부를 확인합니다. NULL이라면 KVS_ERR_PARAM_INVALID을 출력합니다.
- kvs_value 포인터가 NULL이 아니라면, 다음 사항을 모두 체크합니다.
    - 해당 포인터가 가리키는 struct 내의 length에 대해 MAX 길이를 확인합니다. KV API 호출 시 OpenMPDK 내에서 **허용된 value의 길이는 0 이상 2^21 이하**입니다. 이 조건에 맞지 않다면 KVS_ERR_VALUE_LENGTH_INVALID 에러를 반환합니다.
    - value offset alignment 여부를 확인합니다. 하위 8비트가 0인지를 체크하여, **256B 단위로 align**되지 않았다면 KVS_ERR_VALUE_OFFSET_MISALIGNED을 출력합니다.
    - 해당 포인터가 가리키는 struct 내의 value(buffer) 포인터에 대해 NULL 여부를 확인합니다. 값의 길이가 0보다 크면서 NULL이라면 KVS_ERR_PARAM_INVALID을 출력합니다.
    - (Read에서 입력받을 value 포인터에 한해) **length는 4의 배수**여야 합니다. 

제한 상수값에 대한 정보는 [PDK/core/include/kvs_const.h](https://github.com/snu-csl/KVSSD_5.10.37/blob/82cf1e1ecba8bcec256177de2b80d9c9fde87ad4/PDK/core/include/kvs_const.h#L42)를 참고하였습니다.

구현한 API 함수(Read, Update, Insert, Delete)에 대해 입력받은 key, value가 올바른 입력인지 확인하는 함수를 상기 참고하여 따로 구현하도록 하겠습니다.
created_at: 2024-12-05T06:32:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 바로 위 conversation에 대해서도 글을 남겼지만, 간단히 축약하자면

- key, value buffer pointer는 (value 한정 length가 0 초과인 경우) NULL이 아니어야 함.
- key length: 4 이상 255 이하의 정수
- value length: 0 이상 2^21 이하의 정수 (Read()에서 저장할 value 포인터 한정 length는 4의 배수)
- value offset: 256(=2^8)의 배수

과 같은 제약사항이 존재합니다.

Read()에서 value의 length가 4의 배수임을 확인하는 이유는, nvme store 시 데이터의 길이를 4바이트로 조정하여 저장하는 매커니즘을 따르기 때문입니다. (store 시 cdw10를 통해 value->length >> 2를 전달) (참고: [PDK/core/src/device_abstract_layer/kernel_driver_adapter/kadi.cpp](https://github.com/snu-csl/KVSSD_5.10.37/blob/82cf1e1ecba8bcec256177de2b80d9c9fde87ad4/PDK/core/src/device_abstract_layer/kernel_driver_adapter/kadi.cpp#L459))
created_at: 2024-12-05T06:35:48Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+#include "kvssd_hashmap_db.h"
+
+#include <mutex>
+#include <string>
+
+const char *kvstrerror[] = {
+    "Successful",                           // KVS_SUCCESS
+    "Buffer space is not enough",           // KVS_ERR_BUFFER_SMALL
+    "Device does not have enough space",    // KVS_ERR_DEV_CAPAPCITY
+    "No device with the dev_hd exists",     // KVS_ERR_DEV_NOT_EXIST
+    "Key space does not have enough space", // KVS_ERR_KS_CAPACITY
+    "Key space is already created",         // KVS_ERR_KS_EXIST
+    "Index is not valid",                   // KVS_ERR_KS_INDEX
+    "Key space name is not valid",          // KVS_ERR_KS_NAME
+    "Key space does not exist",             // KVS_ERR_KS_NOT_EXIST
+    "Key space does not open",              // KVS_ERR_KS_NOT_OPEN
+    "Key space is already opened",          // KVS_ERR_KS_OPEN
+    "Iterator filter is not valid",         // KVS_ERR_ITERATOR_FILTER_INVALID
+    "Maximum number of iterators opened",   // KVS_ERR_ITERATOR_MAX
+    "Iterator Key Group does not exist",    // KVS_ERR_ITERATOR_NOT_EXIST
+    "Iterator is already opened",           // KVS_ERR_ITERATOR_OPEN
+    "Key is not valid",                     // KVS_ERR_KEY_LENGTH_INVALID
+    "Key does not exist",                   // KVS_ERR_KEY_NOT_EXIST
+    "Option is not supported",              // KVS_ERR_OPTION_INVALID
+    "Null input parameter",                 // KVS_ERR_PARAM_INVALID
+    "I/O error occurs",                     // KVS_ERR_SYS_IO
+    "Value length is out of range",         // KVS_ERR_VALUE_LENGTH_INVALID
+    "Value offset is out of range",         // KVS_ERR_VALUE_OFFSET_INVALID
+    "Value offset is misaligned",           // KVS_ERR_VALUE_OFFSET_MISALIGNED
+    "Value update is not allowed",          // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+    "Device was not opened yet"             // KVS_ERR_DEV_NOT_OPENED
+};
+
+Hashmap_KVSSD::Hashmap_KVSSD()
+{
+    // initialize
+}
+Hashmap_KVSSD::~Hashmap_KVSSD()
+{
+    // cleanup
+}
+
+// API 함수 4가지
+kvs_result Hashmap_KVSSD::Read(const kvs_key &key, kvs_value &value_out)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    value_out = it->second;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Insert(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it != db.end())
+    {
+        return KVS_ERR_KS_EXIST;
+    }
+    db.insert({key, value});
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Update(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    it->second = value;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Delete(const kvs_key &key)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    db.erase(key);
+    return KVS_SUCCESS;
+}
+
+KVSSD *NewKvssdDB()
+{
+    return new Hashmap_KVSSD;
+}
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: 생각해보니 이런 경우라면 NewKvssdDB()로 호출 하는 것보다는 그냥 상위 레이어에서 제작을 하는 것이 맞을 겁니다.

저희가 factory method에 가깝기 때문에 쉽게 구현 가능하실겁니다.
https://refactoring.guru/design-patterns/factory-method
created_at: 2024-12-05T12:58:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: enum class 도입도 고려해볼만 할 것 같습니다.
created_at: 2024-12-05T13:00:11Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: `using namespace ycsbc`를 없애서 namespace ycsbc로 묶는 것도 방법이긴 하지만 통상적인 방식은 사실 아닙니다. namespace안에 namespace는 굉장히 이상합니다.

개인적으로 ycsbc에 의존적인 내용은 `ycsbc::Blah()`로 사용해주시길 바랍니다.
created_at: 2024-12-05T13:09:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: https://github.com/google/googletest/blob/main/googletest/samples/sample10_unittest.cc

namespace 용례 참고입니다. 제가 부분만을 일단은 클릭했지만 전체적으로 감싸주는 것이 좋아요.
created_at: 2024-12-05T13:14:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: typedef enum이 아닌 enum class로 도입하였을 때 얻을 수 있는 이점으로 어떤 것이 있나요?
둘 간에 큰 차이를 잘 못느껴서 질문드립니다.
created_at: 2024-12-05T14:06:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 말씀해 주신대로 수정하겠습니다!
created_at: 2024-12-05T14:08:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 말씀해주신 내용처럼 기존 ycsbc namespace는 지우고 anonymous namespace를 전체적으로 TEST 영역 포함하여 감싼 뒤 ycsbc에 대해서는 의존적인 내용에 대해 각각 명시적으로 표현하려고 하였는데, ycsbc도 DB::Field, utils 등 사용되는 곳이 많다보니 자칫 코드가 길어질 수 있겠다는 생각이 듭니다. 이대로 진행해도 상관 없을까요?
created_at: 2024-12-05T14:18:42Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 즉 길어진다는 것이 한 줄이 길어진다는거죠? `ycsbc::DB::Field`가 될까봐 우려하시는 거라면 상관없습니다. 오히려 이렇게 자료형이 명확한 편이 좀 더 좋습니다. DB::Field라고 하면 ycsbc의 Field인지 저희가 따로 만든 커스텀 클래스인지 구분이 안 가는 것이 좀 더 걱정되는 사항이죠.
created_at: 2024-12-06T04:37:11Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: 요 문서를 참고하시면 좋을 것 같습니다.

https://www.getdunne.net/wiki/doku.php?id=enum_class_rather_than_typedef_enum
created_at: 2024-12-06T04:38:36Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 아 그렇군요!! 저 부분이 길어질까봐 우려되는 부분이 맞습니다. 해당 부분 업데이트하겠습니다.
created_at: 2024-12-06T05:30:22Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+#include "kvssd_hashmap_db.h"
+
+#include <mutex>
+#include <string>
+
+const char *kvstrerror[] = {
+    "Successful",                           // KVS_SUCCESS
+    "Buffer space is not enough",           // KVS_ERR_BUFFER_SMALL
+    "Device does not have enough space",    // KVS_ERR_DEV_CAPAPCITY
+    "No device with the dev_hd exists",     // KVS_ERR_DEV_NOT_EXIST
+    "Key space does not have enough space", // KVS_ERR_KS_CAPACITY
+    "Key space is already created",         // KVS_ERR_KS_EXIST
+    "Index is not valid",                   // KVS_ERR_KS_INDEX
+    "Key space name is not valid",          // KVS_ERR_KS_NAME
+    "Key space does not exist",             // KVS_ERR_KS_NOT_EXIST
+    "Key space does not open",              // KVS_ERR_KS_NOT_OPEN
+    "Key space is already opened",          // KVS_ERR_KS_OPEN
+    "Iterator filter is not valid",         // KVS_ERR_ITERATOR_FILTER_INVALID
+    "Maximum number of iterators opened",   // KVS_ERR_ITERATOR_MAX
+    "Iterator Key Group does not exist",    // KVS_ERR_ITERATOR_NOT_EXIST
+    "Iterator is already opened",           // KVS_ERR_ITERATOR_OPEN
+    "Key is not valid",                     // KVS_ERR_KEY_LENGTH_INVALID
+    "Key does not exist",                   // KVS_ERR_KEY_NOT_EXIST
+    "Option is not supported",              // KVS_ERR_OPTION_INVALID
+    "Null input parameter",                 // KVS_ERR_PARAM_INVALID
+    "I/O error occurs",                     // KVS_ERR_SYS_IO
+    "Value length is out of range",         // KVS_ERR_VALUE_LENGTH_INVALID
+    "Value offset is out of range",         // KVS_ERR_VALUE_OFFSET_INVALID
+    "Value offset is misaligned",           // KVS_ERR_VALUE_OFFSET_MISALIGNED
+    "Value update is not allowed",          // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+    "Device was not opened yet"             // KVS_ERR_DEV_NOT_OPENED
+};
+
+Hashmap_KVSSD::Hashmap_KVSSD()
+{
+    // initialize
+}
+Hashmap_KVSSD::~Hashmap_KVSSD()
+{
+    // cleanup
+}
+
+// API 함수 4가지
+kvs_result Hashmap_KVSSD::Read(const kvs_key &key, kvs_value &value_out)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    value_out = it->second;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Insert(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it != db.end())
+    {
+        return KVS_ERR_KS_EXIST;
+    }
+    db.insert({key, value});
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Update(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    it->second = value;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Delete(const kvs_key &key)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    db.erase(key);
+    return KVS_SUCCESS;
+}
+
+KVSSD *NewKvssdDB()
+{
+    return new Hashmap_KVSSD;
+}
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: 네, 알겠습니다.
created_at: 2024-12-06T06:03:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: namespace 관련하여 한 가지 더 질문이 있습니다.
지금까지 kvssd_hashmap_db_impl.cc와 헤더 파일에서 제가 만든 class, 함수들은 모두 ycsbc에 포함하였는데(전체를 namespace ycsbc에 감싸는 방식으로) 해당 개체들은 그대로 ycsbc namespace에 유지하는 것보다는 새 namespace를 만드는 것이 나을까요??
created_at: 2024-12-06T13:32:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 보내주신 문서 링크에서 1번째 방식이 enum class를 사용하는 것으로 보이는데, 혹시 2번째 방식처럼 KVSSD class(interface) 내부에 protected 형으로 enum 자료형을 넣는 방식은 어떨지 건의드립니다. 
created_at: 2024-12-06T14:02:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: ```c++
namespace {
  const std::string PROP_DBPATH = "lmdb.dbpath";
  const std::string PROP_DBPATH_DEFAULT = "";

  const std::string PROP_MAPSIZE = "lmdb.mapsize";
  const std::string PROP_MAPSIZE_DEFAULT = "-1";

  const std::string PROP_NOSYNC = "lmdb.nosync";
  const std::string PROP_NOSYNC_DEFAULT = "false";

  const std::string PROP_NOMETASYNC = "lmdb.nometasync";
  const std::string PROP_NOMETASYNC_DEFAULT = "false";

  const std::string PROP_NORDAHEAD = "lmdb.noreadahead";
  const std::string PROP_NORDAHEAD_DEFAULT = "false";

  const std::string PROP_WRITEMAP = "lmdb.writemap";
  const std::string PROP_WRITEMAP_DEFAULT = "false";

  const std::string PROP_MAPASYNC = "lmdb.mapasync";
  const std::string PROP_MAPASYNC_DEFAULT = "false";
} // anonymous
``` 

위에서 말씀드린 lmdb_db.cc 내부의 anonymous namespace가 위와 같은데, 해당 코드를 참고하는 것이 맞는지 확인 차 여쭤봅니다. properties 파일에서 값 설정이 가능한 항목들입니다만, kvssd에서의 사용 필요성을 못 느껴서요
created_at: 2024-12-06T14:16:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: [질문1] 혹시 multithreading 환경에서의 단위 테스트도 gtest에서 가능한가요?
현재 동시에 test를 몇 개까지 돌릴 수 있는지 설정하는 항목은 vscode 확장 프로그램의 settings.json에서 찾긴 했는데, 해당 변수가 하나의 db(hashmap)에 대한 multithreading test인지는 확신이 가지 않습니다.
created_at: 2024-12-06T14:19:51Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: [질문2] RWLock을 사용하기 위해 ReadersWriterLock.h 파일을 꽤 많이 참고하게 될 것 같은데, 해당 파일에 대한 출처를 명시할 필요가 있을까요?
created_at: 2024-12-06T14:30:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+#include "kvssd_hashmap_db.h"
+
+#include <mutex>
+#include <string>
+
+const char *kvstrerror[] = {
+    "Successful",                           // KVS_SUCCESS
+    "Buffer space is not enough",           // KVS_ERR_BUFFER_SMALL
+    "Device does not have enough space",    // KVS_ERR_DEV_CAPAPCITY
+    "No device with the dev_hd exists",     // KVS_ERR_DEV_NOT_EXIST
+    "Key space does not have enough space", // KVS_ERR_KS_CAPACITY
+    "Key space is already created",         // KVS_ERR_KS_EXIST
+    "Index is not valid",                   // KVS_ERR_KS_INDEX
+    "Key space name is not valid",          // KVS_ERR_KS_NAME
+    "Key space does not exist",             // KVS_ERR_KS_NOT_EXIST
+    "Key space does not open",              // KVS_ERR_KS_NOT_OPEN
+    "Key space is already opened",          // KVS_ERR_KS_OPEN
+    "Iterator filter is not valid",         // KVS_ERR_ITERATOR_FILTER_INVALID
+    "Maximum number of iterators opened",   // KVS_ERR_ITERATOR_MAX
+    "Iterator Key Group does not exist",    // KVS_ERR_ITERATOR_NOT_EXIST
+    "Iterator is already opened",           // KVS_ERR_ITERATOR_OPEN
+    "Key is not valid",                     // KVS_ERR_KEY_LENGTH_INVALID
+    "Key does not exist",                   // KVS_ERR_KEY_NOT_EXIST
+    "Option is not supported",              // KVS_ERR_OPTION_INVALID
+    "Null input parameter",                 // KVS_ERR_PARAM_INVALID
+    "I/O error occurs",                     // KVS_ERR_SYS_IO
+    "Value length is out of range",         // KVS_ERR_VALUE_LENGTH_INVALID
+    "Value offset is out of range",         // KVS_ERR_VALUE_OFFSET_INVALID
+    "Value offset is misaligned",           // KVS_ERR_VALUE_OFFSET_MISALIGNED
+    "Value update is not allowed",          // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+    "Device was not opened yet"             // KVS_ERR_DEV_NOT_OPENED
+};
+
+Hashmap_KVSSD::Hashmap_KVSSD()
+{
+    // initialize
+}
+Hashmap_KVSSD::~Hashmap_KVSSD()
+{
+    // cleanup
+}
+
+// API 함수 4가지
+kvs_result Hashmap_KVSSD::Read(const kvs_key &key, kvs_value &value_out)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    value_out = it->second;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Insert(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it != db.end())
+    {
+        return KVS_ERR_KS_EXIST;
+    }
+    db.insert({key, value});
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Update(const kvs_key &key, const kvs_value &value)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    it->second = value;
+    return KVS_SUCCESS;
+}
+
+kvs_result Hashmap_KVSSD::Delete(const kvs_key &key)
+{
+    auto it = db.find(key);
+    if (it == db.end())
+    {
+        return KVS_ERR_KS_NOT_EXIST;
+    }
+    db.erase(key);
+    return KVS_SUCCESS;
+}
+
+KVSSD *NewKvssdDB()
+{
+    return new Hashmap_KVSSD;
+}
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: 해당 내용 반영하였습니다.
`NewKvssdDB()` 함수 관련 부분은 전부 삭제하였습니다.
`kvssd_test.cc`에서 Hashmap_KVSSD 인스턴스를 아래와 같이 생성합니다.
`std::unique_ptr<KVSSD> kvssd(new Hashmap_KVSSD());`
created_at: 2024-12-06T15:09:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: [질문3] 일단은 출처 명시 생략하고 RWLock을 통해 critical section 처리하였습니다.
관련하여 질문이 있는데요, std::shared_mutex 대신 RWLock을 사용하는데 얻는 이점이 궁금합니다.
created_at: 2024-12-06T15:10:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 관련하여 ValidateRequest() 함수 추가하였습니다.
created_at: 2024-12-06T19:31:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 관련하여 `ValidateRequest()` 함수 추가하였습니다.
created_at: 2024-12-06T19:32:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: include 관련하여 수정 완료하였습니다.
현재까지 제작한 TEST, 메모리 누수 체크 모두 정상입니다.
TEST끼리 간헐적으로 서로 다른 DB에 간섭하는 문제를 방지하기 위한 class를 새로 만들었습니다.
created_at: 2024-12-06T19:34:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 일단 현재는 enum class로 적용 완료한 상태입니다.
created_at: 2024-12-06T19:46:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 수정 완료하였습니다.
created_at: 2024-12-06T19:48:11Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: + 현재 ycsbc 관련 개체는 전부 명시적으로 수정 완료하였습니다.
created_at: 2024-12-06T19:48:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: > multithreading 환경에서의 단위 테스트도 gtest에서 가능한가요?

동시에 테스트를 돌리는 것이 아니라 thread를 여러 개를 단일 테스트 안에서 만들어서 테스트 하는 방식이라고 생각하시면 될 것 같습니다.

> RWLock을  사용하기 위해 Reader...

보통 posix 라이브러리를 많이 사용합니다. 이 경우에는 해당 코드를 참고할 필요 없습니다. pthread.h를 넣어주고 라이브러리를 바인딩 해주시면 됩니다.

https://kukuta.tistory.com/35

> std::shared_mutex 대신 RWLock을 사용하는데 얻는 이점이 궁금합니다.

다음 운영체제 교재의 31.5를 확인하면 좋을 것 같습니다!

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-sema.pdf

성능 관련해서 좋은 참고 자료가 있기에 공유드립니다. https://turingcompl33t.github.io/RWLock-Benchmark/
created_at: 2024-12-16T14:56:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: 그냥 namespace로 묶어 주시기만 하면 됩니다. 코드를 넣어주실 필요가 없습니다.

즉, 코드를

```cpp
<code>
<code>
```

에서

```cpp
namespace {
  <code>
  <code>
}
```

로 변경하시면 됩니다.
created_at: 2024-12-16T15:00:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: `ValidateRequest()` 함수가 public일 필요는 없을 것으로 보입니다. 추가로 인터페이스화 하는 것도 필요해보이지는 않습니다. Read, Update, Insert, Delete가 실행될 때에 확인이 들어가는 것이니까요!
created_at: 2024-12-16T15:02:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: BlaCkinkGJ
body: https://github.com/veritross/YCSB-cpp/pull/5#discussion_r1886973481
created_at: 2024-12-16T15:02:48Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 참고로 테스트에서 setup 및 teardown 용도에 관해서 좀 더 관심이 있으시다면 문서 참고해주시면 좋을 것 같아요!!

https://github.com/google/googletest/blob/main/docs/primer.md
created_at: 2024-12-16T15:07:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: > 지금까지 kvssd_hashmap_db_impl.cc와 헤더 파일에서 제가 만든 class, 함수들은 모두 ycsbc에 포함하였는데(전체를 namespace ycsbc에 감싸는 방식으로) 해당 개체들은 그대로 ycsbc namespace에 유지하는 것보다는 새 namespace를 만드는 것이 나을까요??

~~아마 ycsbc로 묶어주는 것이 좋을 것 같습니다. lmdb와 leveldb 둘 다, namespace ycsbc { .. } 로 묶어 주네요. 즉, 외부로 노출되는 친구들은 namespace ycsbc로 묶어주시고, 노출되지 않는 것은 anonymous namespace로 묶어주시면 됩니다!~~ 새로운 namespace가 좀 더 명시적으로 보이기 때문에 그렇게 하는 것이 좋을 것 같습니다. 예를 들어 kvssd_hashmap이 좋을 것 같네요.
created_at: 2024-12-16T15:09:58Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,110 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <cstring>
+#include <cstdint>
+#include <unordered_map>
+
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: > 보내주신 문서 링크에서 1번째 방식이 enum class를 사용하는 것으로 보이는데, 혹시 2번째 방식처럼 KVSSD class(interface) 내부에 protected 형으로 enum 자료형을 넣는 방식은 어떨지 건의드립니다.

interface에 구체화된 데이터가 들어가는 것은 조금 느낌이 이상하긴 합니다.


created_at: 2024-12-16T15:18:52Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: 말씀주신대로 `ValidateRequest()` 함수는 private로 변경하였고, KVSSD 인터페이스에서도 제거하였습니다.
created_at: 2024-12-17T15:40:14Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+#include "bits/stdc++.h"
+#include "kvssd_hashmap_db.h"
+
+/**
+ * @brief key, value struct의 unique_ptr를 원소로 하는 구조체
+ */
+struct kvs_row
+{
+    std::unique_ptr<kvs_key> key;
+    std::unique_ptr<kvs_value> value;
+};
+
+/**
+ * @brief Field vector to string pointer
+ * @param[in] values string으로 변환할 vector<Field>
+ * @param[out] data 변환된 값을 저장할 string 포인터
+ */
+void SerializeRow(const std::vector<Field> &values, std::string *data)
+{
+    for (const Field &field : values)
+    {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+/**
+ * @brief char* to Field vector pointer
+ * @param[out] values 변환된 값을 저장할 vector<Field> pointer
+ * @param[in] data_ptr vector<Field>으로 변환할 char*의 위치
+ * @param[in] data_len 변환할 char*의 길이
+ */
+void DeserializeRow(std::vector<Field> *values, const char *data_ptr, size_t data_len)
+{
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim)
+    {
+        assert(p < lim);
+        uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(len));
+        p += len;
+        len = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(len));
+        p += len;
+        values->push_back({field, value});
+    }
+    // assert(values->size() == field_count_);
+}
+
+/**
+ * @brief 새 row를 생성하는 함수
+ * @param[in] key_in 새 key를 담은 문자열
+ * @param[in] value_in 새 value를 담은 vector<Field>
+ * @return 새 row의 unique pointer
+ */
+std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<Field> &value_in)
+{
+    std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+
+    newRow->key = std::make_unique<kvs_key>();
+    char *key_data = new char[key_in.size()];
+    std::memcpy(key_data, key_in.data(), key_in.size());
+    newRow->key->key = static_cast<void *>(key_data);
+    newRow->key->length = key_in.size();
+
+    newRow->value = std::make_unique<kvs_value>();
+    std::string value_sz;
+    SerializeRow(value_in, &value_sz);
+    char *value_data = new char[value_sz.size()];
+    std::memcpy(value_data, value_sz.data(), value_sz.size());
+    newRow->value->value = static_cast<void *>(value_data);
+    newRow->value->length = value_sz.size();
+    newRow->value->actual_value_size = value_sz.size();
+    newRow->value->offset = 0;
path: kvssd/kvssd_hashmap_db_run.cc
user: login: easter423
body: [#5 (comment)](https://github.com/veritross/YCSB-cpp/pull/5#discussion_r1888730621)
created_at: 2024-12-17T15:41:01Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: kvssd_hashmap namespace로 묶는 것을 `kvssd_hashmap_db.h`, `kvssd_hashmap_db.cc`, `kvssd_hashmap_db_impl.h`, `kvssd_hashmap_db_impl.cc` 4개의 파일에 반영하였습니다.
기존 `ycsbc` namespace로 묶은 것은 풀어준 뒤 필요한 부분에 대해서는 `ycsbc::`로 명시적으로 표기하였습니다.

다만 `KVSSD` interface같이 hashmap에 국한되지 않는 부분에 대해서는 `kvssd_hashmap` namespace로 묶는 것이 어울리지 않다고 보는데, 이때는 어떻게 처리하는 것이 좋나요? (일단 `kvssd_hashmap` namespace에 추가하였습니다.)
created_at: 2024-12-17T16:15:11Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+#ifndef YCSB_C_KVSSD_HASHMAP_DB_H_
+#define YCSB_C_KVSSD_HASHMAP_DB_H_
+
+#include <unordered_map>
+#include <cstring>
+
+#include <kvssd.h>
+
+/**
+ * @brief kvssd API 함수의 반환 자료형
+ */
+typedef enum
+{
+    KVS_SUCCESS = 0,                          // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,             // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,            // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,            // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,              // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,                 // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,                 // index is not valid
+    KVS_ERR_KS_NAME = 0x007,                  // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,             // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,              // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,                  // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID = 0x00B,  // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,             // the maximum number of iterators that a device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,       // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,            // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,       // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,            // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,           // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,            // null input parameter
+    KVS_ERR_SYS_IO = 0x013,                   // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,     // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,     // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED = 0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017, // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,           // device was not opened yet
+} kvs_result;
+
+/**
+ * @brief kvs_result을 Index, 대응되는 에러문을 Value로 갖는 배열
+ */
+extern const char *kvstrerror[];
+
+/**
+ * @brief DB row의 Value vector의 원소 타입
+ */
+struct Field
+{
+    std::string name;
+    std::string value;
+};
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: https://github.com/veritross/YCSB-cpp/pull/5#discussion_r1888816619
created_at: 2024-12-17T16:16:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: posix 라이브러리로 rwlock 전환 완료하였습니다.
multithreading gtest 현재진행중입니다.
created_at: 2024-12-17T17:29:18Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: multithread 관련하여 gtest를 추가하였습니다. (아직 repo에 PR하지는 않음)

본 테스트 과정에서 문제를 발견하였습니다. KVSSD 내부적으로는 API 동작 시 병렬성에 문제가 없는데, hashmap kvssd를 위해 사용되는 db_impl.cc에서 API를 실행하기 전 key-value struct를 unique pointer 형태로 만들 때 문제가 발생합니다. 이 unique pointer를 함수 밖에서도 유지할 수 있도록 vector list에 해당 포인터를 push_back 하는 방식을 사용하는데, 해당 부분에서 병렬성이 지켜지지 않았습니다.

해당 부분(vector push_back)을 mutex lock으로 감싸주면 병렬성 문제는 해결되지만 multithread를 사용하지 않는 모든 test에서도 시간이 10배정도 더 걸리는 것을 확인할 수 있었는데, 이 경우 그대로 두어도 괜찮을까요?
(대략 100,000개 정도의 key value API 동작에 2초 가량 소요됩니다.)
created_at: 2024-12-18T03:33:57Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: > 이 unique pointer를 함수 밖에서도 유지할 수 있도록 vector list에 해당 포인터를 push_back 하는 방식을 사용하는데, 해당 부분에서 병렬성이 지켜지지 않았습니다.

`GetInstance().memoryList.push_back(std::move(memory));` 부분을 말씀하시는 것일까요?

> (대략 100,000개 정도의 key value API 동작에 2초 가량 소요됩니다.)

혹시 가능하시다면 RocksDB나 다른 DB에서 몇 초 정도 걸리는지 확인이 가능할까요?
created_at: 2024-12-18T13:22:49Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 이럴 때에는 저는 보통 best practice로 삼을만한 코드를 확인합니다. LevelDB의 경우에는 namepsace로 묶기는 하군요.

https://github.com/google/leveldb/blob/23e35d792b9154f922b8b575b12596a4d8664c65/include/leveldb/cache.h

인터페이스에 관해서는 `kvssd_hashmap`이라는 이름은 좀 이상하니까 `namespace kvssd`가 어떨까요? 그리고 파일을 kvssd.cc로 분리하는 것도 좋을 것 같습니다.
created_at: 2024-12-18T13:26:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: > `GetInstance().memoryList.push_back(std::move(memory));` 부분을 말씀하시는 것일까요?

네, 맞습니다.

> 혹시 가능하시다면 RocksDB나 다른 DB에서 몇 초 정도 걸리는지 확인이 가능할까요?

확실하게 이해를 잘 못했는데, 제가 만든 KV API를 현재 hashmap을 다른 DB로 대체해서 테스트하는 걸 말씀하시는 건가요?

created_at: 2024-12-18T13:28:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 감사합니다.

아직 인터페이스 외의 구현은 없어서 kvssd.cc 대신 헤더파일만 만들어도 상관 없을까요?
created_at: 2024-12-18T13:30:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: ```
[BlaCkinkGJ] [오후 11:11] 혹시 가능하다면 상위 레이어에서 RocksDB를 돌려보시면 좋을 것 같아요. 안 그러면 아마도 개발에 공수가 좀 더 들어갈 것 같아요.
[BlaCkinkGJ] [오후 11:11] 현재 YCSB Interface -> DB -> DB_internal로 되어있잖아요.
[BlaCkinkGJ] [오후 11:12] 여기서 YCSB Interface -> RocksDB로 I/O 성능을 확인하고
YCSB Interface -> KVSSD DB -> ...로 성능을 확인하는 것이죠
[easter423] [오후 11:19] 그러면 gtest 말고 YCSB에서 원래 제공하는 workload 사용해서 실행하는 거로 이해하면 될까요?
[BlaCkinkGJ] [오후 11:20] 그래도 좋을 것 같고요. 그게 귀찮다면 gtest로 하시는 것도 괜찮아요!!
[BlaCkinkGJ] [오후 11:20] 편하신 방법으로 해보시죠.
[easter423] [오후 11:20] 아 두 방법 전부 상관없군요
[BlaCkinkGJ] [오후 11:21] 다름 아니라, 일반적인 DB 대비해서 성능이 어느정도인지를 확인하고 싶은 상황입니다.

100,000개에 2초면 50,000 IOPS라고 볼 수 있을 것 같은데, 이렇게 나오는 것이 옳은 것이 확인하기 위함이에요!
```

추가로 만약에 성능이 필요하다면 lock-free list도 찾아보면 좋을 것 같습니다.

created_at: 2024-12-18T14:31:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: 그리고 병렬성이 아니라 동시성을 말씀하시는 것 같습니다.
created_at: 2024-12-18T14:32:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,224 @@
+#include "gtest/gtest.h"
+#include "../kvssd_hashmap_db_impl.h"
+
+#include <ctime>
+#include <string>
+
+#define NUM_KEYS 1000
+#define NUM_VALUES 1000
+
+using namespace ycsbc;
+
+std::string RandomPrintStr(size_t length)
+{
+
+    std::string randomString;
+    randomString.reserve(length);
+    for (size_t i = 0; i < length; ++i)
+    {
+        randomString += utils::RandomPrintChar();
+    }
+    return randomString;
+}
+
+std::vector<std::string> key = []
+{
+    std::vector<std::string> keys(NUM_KEYS);
+    for (size_t i = 0; i < NUM_KEYS; i++)
+    {
+        keys[i] = "key" + std::to_string(i);
+    }
+    return keys;
+}();
+
+std::vector<std::vector<DB::Field>> value = []
+{
+    srand(static_cast<unsigned>(time(0)));
+    std::vector<std::vector<DB::Field>> values(NUM_VALUES);
+    for (size_t i = 0; i < NUM_VALUES; i++)
+    {
+        values[i] = {
+            {"field" + std::to_string(i) + "_1", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_2", "value" + std::to_string(i) + RandomPrintStr(32)},
+            {"field" + std::to_string(i) + "_3", "value" + std::to_string(i) + RandomPrintStr(32)}};
+    }
+    return values;
+}();
+
+std::vector<DB::Field> output_value;
+
+std::unique_ptr<KVSSD> kvssd(NewKvssdDB());
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 그래도 상관없을 것 같습니다!
created_at: 2024-12-18T14:34:04Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: kvssd_hashmap_db.h -> (kvssd_hashmap_db.h, kvssd.h)로 분리해야 합니다.

interface와 기본이 되는 자료구조에 해당하는 친구는 kvssd.h로 이동하고, interface가 아닌 친구들은 kvssd_hashmap_db.h로 가면 됩니다.
created_at: 2024-12-26T11:41:15Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db.h
user: login: BlaCkinkGJ
body: 그리고 kvssd.cc 파일을 만들어주는데요. 이 친구는 간단하게 다음처럼 만들면 될 것 같아요.

```cpp
namespace {
  const std::string PROP_BACKEND= "kvssd.backend";
  const std::string PROP_BACKEND_DEFAULT = "kvssd";
} // anonymous

DB *NewKvssdDB() {
  // 어쩌고 저쩌고
  // https://github.com/veritross/YCSB-cpp/blob/86ee150e8946bcac2a6b909d8fef4939d8d5ae61/lmdb/lmdb_db.cc#L58-L88
  string backend = ~~;
  DB *ret = nullptr;
  if (backend == "hashmap") {
      // constructor로 초기화
      ret = new HashMap("test");
  }
  if (backend == "kvssd") {
     ret = new Kvssd("test", "test");
  }
  return ret;
}

const bool registered = DBFactory::RegisterDB("kvssd", NewKvssdDB);
```
created_at: 2024-12-26T11:46:43Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
+    }
+
+    std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<ycsbc::DB::Field> &value_in)
+    {
+        std::unique_ptr<char[]> key_data = std::make_unique<char[]>(key_in.size());
+        std::memcpy(key_data.get(), key_in.data(), key_in.size());
+        void *key = static_cast<void *>(key_data.get());
+        uint16_t key_length = key_in.size();
+
+        std::string value_sz;
+        SerializeRow(value_in, &value_sz);
+
+        std::unique_ptr<char[]> value_data = std::make_unique<char[]>(value_sz.size());
+        std::memcpy(value_data.get(), value_sz.data(), value_sz.size());
+
+        void *value = static_cast<void *>(value_data.get());
+        uint32_t value_length = value_sz.size();
+        uint32_t actual_value_size = value_sz.size();
+        uint32_t offset = 0;
+
+        std::unique_ptr<kvs_key> newKey = std::make_unique<kvs_key>();
+        newKey->key = key;
+        newKey->length = key_length;
+
+        std::unique_ptr<kvs_value> newValue = std::make_unique<kvs_value>();
+        newValue->value = static_cast<void *>(value_data.get());
+        newValue->length = value_sz.size();
+        newValue->actual_value_size = value_sz.size();
+        newValue->offset = 0;
+
+        std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+        newRow->key = std::move(newKey);
+        newRow->value = std::move(newValue);
+
+        ManagedMemory::Add(std::move(key_data));
+        ManagedMemory::Add(std::move(value_data));
+
+        return newRow;
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: BlaCkinkGJ
body: ```suggestion
        uint16_t key_length = key_in.size();
        void *key = malloc(key_length);
        std::memcpy(key, (void *)(key_in.data()), key_length);

        std::string value_sz;
        SerializeRow(value_in, &value_sz);

        void *value = malloc(value_sz.size());
        std::memcpy(value, value_sz.data(), value_sz.size());

        uint32_t value_length = value_sz.size();
        uint32_t actual_value_size = value_sz.size();
        uint32_t offset = 0;

        std::unique_ptr<kvs_key> newKey = std::make_unique<kvs_key>();
        newKey->key = key;
        newKey->length = key_length;

        std::unique_ptr<kvs_value> newValue = std::make_unique<kvs_value>();
        newValue->value = value;
        newValue->length = value_sz.size();
        newValue->actual_value_size = value_sz.size();
        newValue->offset = 0;

        std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
        newRow->key = std::move(newKey);
        newRow->value = std::move(newValue);

        return newRow;
```
created_at: 2025-01-15T12:21:22Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: BlaCkinkGJ
body: ```
free(p);
```

`std::string`에 이미 p의 내용이 할당이 되었기 때문에 `data_ptr` 내용이 free되어도 문제 없지 않을까요? 테스트 필요.
created_at: 2025-01-15T12:27:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: BlaCkinkGJ
body: p를 해제하고 string 값을 읽었을 때 이상한 값이 나오면 해제하면 안됩니다. 그 경우에는 복사해야합니다.
created_at: 2025-01-15T12:27:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: BlaCkinkGJ
body: `Read` 내부 구현을 보고 dealloc을 해야 합니다.
created_at: 2025-01-15T12:31:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: easter423
body: 변경한 CreateRow()에 맞춰 메모리 해제 관련 해결하였습니다.
kvs_key, kvs_value는 앞으로 스마트 포인터를 사용하지 않되, 해제가 되는 경우 내부 *void 까지 같이 free되도록 조치하였습니다.
kvs_row는 kvs_key, kvs_value를 일반 포인터로 가지되, 스마트 포인터를 std::unique_ptr<kvs_row, KvsRowDeleter>와 같이 생성하여 커스텀 deleter를 활용, unique pointer가 해제될 때 내부적으로 어떻게 해제될 지 KvsRowDeleter에서 따로 구현하였습니다.
hashmap db에 값을 넣기 전 deepcopy를 진행합니다. 이후, 필요가 없어진 kvs_row는 unique_ptr 동작 방식에 의해 자동으로 free됩니다.
불필요해진 MemoryList를 삭제하였습니다.
created_at: 2025-02-04T17:44:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,147 @@
+#include "kvssd_hashmap_db_impl.h"
+
+namespace kvssd_hashmap
+{
+
+    // Field vector to string pointer
+    void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data)
+    {
+        for (const ycsbc::DB::Field &field : values)
+        {
+            uint32_t len = field.name.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.name.data(), field.name.size());
+            len = field.value.size();
+            data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+            data->append(field.value.data(), field.value.size());
+        }
+    }
+
+    // char* to Field vector pointer
+    void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len)
+    {
+        const char *p = data_ptr;
+        const char *lim = p + data_len;
+        while (p != lim)
+        {
+            assert(p < lim);
+            uint32_t len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string field(p, static_cast<const size_t>(len));
+            p += len;
+            len = *reinterpret_cast<const uint32_t *>(p);
+            p += sizeof(uint32_t);
+            std::string value(p, static_cast<const size_t>(len));
+            p += len;
+            values->push_back({field, value});
+        }
+    }
+
+    std::unique_ptr<kvs_row> CreateRow(const std::string &key_in, const std::vector<ycsbc::DB::Field> &value_in)
+    {
+        std::unique_ptr<char[]> key_data = std::make_unique<char[]>(key_in.size());
+        std::memcpy(key_data.get(), key_in.data(), key_in.size());
+        void *key = static_cast<void *>(key_data.get());
+        uint16_t key_length = key_in.size();
+
+        std::string value_sz;
+        SerializeRow(value_in, &value_sz);
+
+        std::unique_ptr<char[]> value_data = std::make_unique<char[]>(value_sz.size());
+        std::memcpy(value_data.get(), value_sz.data(), value_sz.size());
+
+        void *value = static_cast<void *>(value_data.get());
+        uint32_t value_length = value_sz.size();
+        uint32_t actual_value_size = value_sz.size();
+        uint32_t offset = 0;
+
+        std::unique_ptr<kvs_key> newKey = std::make_unique<kvs_key>();
+        newKey->key = key;
+        newKey->length = key_length;
+
+        std::unique_ptr<kvs_value> newValue = std::make_unique<kvs_value>();
+        newValue->value = static_cast<void *>(value_data.get());
+        newValue->length = value_sz.size();
+        newValue->actual_value_size = value_sz.size();
+        newValue->offset = 0;
+
+        std::unique_ptr<kvs_row> newRow = std::make_unique<kvs_row>();
+        newRow->key = std::move(newKey);
+        newRow->value = std::move(newValue);
+
+        ManagedMemory::Add(std::move(key_data));
+        ManagedMemory::Add(std::move(value_data));
+
+        return newRow;
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: easter423
body: 변경 완료하였습니다.
created_at: 2025-02-04T17:45:09Z
author_association: COLLABORATOR
path: kvssd/kvssd_hashmap_db.h
user: login: easter423
body: 변경 완료하였습니다.
created_at: 2025-02-04T17:45:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,90 @@
+#include <string>
+#include <mutex>
+#include "kvssd_hashmap_db.h"
path: kvssd/kvssd_hashmap_db.cc
user: login: easter423
body: CreateRow() 변경 등으로 동시성 문제 해결하였습니다.
기존의 Managed Memory List 등의 방식을 제거하고, 대신 unique ptr이 필요한 상황까지는 유지할 수 있도록 코드를 수정하였습니다. 테스트 결과 속도는 기존의 2배 가량 증가한 것을 확인하였습니다.
created_at: 2025-02-04T17:48:03Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,137 @@
+#include "kvssd_hashmap_db.h"
+
+#include <string>
+
+namespace kvssd_hashmap {
+
+Hashmap_KVSSD::Hashmap_KVSSD() { pthread_rwlock_init(&rwl, NULL); }
+Hashmap_KVSSD::~Hashmap_KVSSD() {
+    for (auto &entry : db) {
+        auto it = db.find(entry.first);
+        if (entry.first.key != nullptr) {
+            free(entry.first.key);
+        }
+        if (entry.second.value != nullptr) {
+            free(entry.second.value);
+        }
+        db.erase(it);
+    }
+    db.clear();
+    pthread_rwlock_destroy(&rwl);
+}
+
+kvssd::kvs_result Hashmap_KVSSD::ValidateRequest(
+    const kvssd::kvs_key &key,
+    std::optional<std::reference_wrapper<const kvssd::kvs_value>> value) {
+    if (key.length < KVS_MIN_KEY_LENGTH || KVS_MAX_KEY_LENGTH < key.length) {
+        return kvssd::kvs_result::KVS_ERR_KEY_LENGTH_INVALID;
+    }
+    if (key.key == NULL) {
+        return kvssd::kvs_result::KVS_ERR_PARAM_INVALID;
+    }
+    if (value) {
+        if (value->get().length < KVS_MIN_VALUE_LENGTH ||
+            KVS_MAX_VALUE_LENGTH < value->get().length) {
+            return kvssd::kvs_result::KVS_ERR_KEY_LENGTH_INVALID;
+        }
+        if (value->get().offset & (KVS_ALIGNMENT_UNIT - 1)) {
+            return kvssd::kvs_result::KVS_ERR_VALUE_OFFSET_MISALIGNED;
+        }
+        if (value->get().value == NULL && value->get().length) {
+            return kvssd::kvs_result::KVS_ERR_PARAM_INVALID;
+        }
+    }
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_key Hashmap_KVSSD::DeepCopyKey(const kvssd::kvs_key &orig) {
+    kvssd::kvs_key copy;
+    copy.length = orig.length;
+    copy.key = malloc(orig.length);
+    if (copy.key && orig.key) {
+        std::memcpy(copy.key, orig.key, orig.length);
+    }
+    return copy;
+}
+
+kvssd::kvs_value Hashmap_KVSSD::DeepCopyValue(const kvssd::kvs_value &orig) {
+    kvssd::kvs_value copy;
+    copy.length = orig.length;
+    copy.actual_value_size = orig.actual_value_size;
+    copy.offset = orig.offset;
+    copy.value = malloc(orig.length);
+    if (copy.value && orig.value) {
+        std::memcpy(copy.value, orig.value, orig.length);
+    }
+    return copy;
+}
+
+// API 함수 4가지
+kvssd::kvs_result Hashmap_KVSSD::Read(const kvssd::kvs_key &key, kvssd::kvs_value &value_out) {
+    kvssd::kvs_result ret = ValidateRequest(key, value_out);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_rdlock(&rwl);
+    auto it = db.find(key);
+    pthread_rwlock_unlock(&rwl);
+    if (it == db.end()) {
+        return kvssd::kvs_result::KVS_ERR_KS_NOT_EXIST;
+    }
+    value_out = it->second;
+    return kvssd::kvs_result::KVS_SUCCESS;
+}
+
+kvssd::kvs_result Hashmap_KVSSD::Insert(const kvssd::kvs_key &key, const kvssd::kvs_value &value) {
+    kvssd::kvs_result ret = ValidateRequest(key, value);
+    if (ret != kvssd::kvs_result::KVS_SUCCESS) {
+        return ret;
+    }
+    pthread_rwlock_wrlock(&rwl);
+    auto it = db.find(key);
+    if (it != db.end()) {
+        pthread_rwlock_unlock(&rwl);
+        return kvssd::kvs_result::KVS_ERR_KS_EXIST;
+    }
+    kvssd::kvs_key key_copy = DeepCopyKey(key);
+    kvssd::kvs_value value_copy = DeepCopyValue(value);
+
+    db.insert({key_copy, value_copy});
path: kvssd/kvssd_hashmap_db.cc
user: login: BlaCkinkGJ
body: 향후에 이것만 교체하기 위함
created_at: 2025-03-29T11:21:19Z
author_association: COLLABORATOR
diff_hunk: @@ -264,12 +264,7 @@ void ParseCommandLine(int argc, const char *argv[], ycsbc::utils::Properties &pr
       }
       std::string filename(argv[argindex]);
       std::ifstream input(argv[argindex]);
-      try {
-        props.Load(input);
-      } catch (const std::string &message) {
-        std::cerr << message << std::endl;
-        exit(0);
-      }
+      props.Load(input);
path: core/ycsbc.cc
user: login: BlaCkinkGJ
body: 혹시 try - catch 부분을 왜 삭제를 했나요?
created_at: 2025-04-27T00:30:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.10)
+project(hashmap-kvssd)
+set(CMAKE_CXX_STANDARD 17)
+enable_testing()
+
+set(CMAKE_BUILD_TYPE Release)
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        )
+        
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g")
+        
+set(TARGET_APP kvssd_test)
+set(SrcLib SrcLib)
+set(SrcFiles kvssd_hashmap_db_impl.cc kvssd_hashmap_db.cc kvssd.cc)
+
+add_library(${SrcLib} STATIC ${SrcFiles})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+add_subdirectory(googletest-1.15.2)
+add_executable(${TARGET_APP} test/kvssd_test.cc)
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+target_link_libraries(${TARGET_APP} gtest_main ${SrcLib})
+
+include(GoogleTest)
+gtest_discover_tests(${TARGET_APP})
+
+# Valgrind memcheck 설정 및 테스트 등록
path: kvssd/CMakeLists.txt
user: login: BlaCkinkGJ
body: 주석 삭제 또는 변경이 필요할 것 같아요. 🙇 
created_at: 2025-04-27T00:31:07Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,56 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    if (backend == "kvssd") {
+        // TODO: ret = new kvssd::KVSSD();
+    }
path: kvssd/kvssd.cc
user: login: BlaCkinkGJ
body: 전체 부분을 주석 처리 하는 것은 어떨까요? 이렇게 하는 경우에 브랜치 구문이 불필요하게 어셈블리 단위로 만들어질 것 같습니다. SonarQube를 사용을 해야하나 싶군요. 🤔 
created_at: 2025-04-27T00:32:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+#ifndef YCSB_C_KVSSD_H_
+#define YCSB_C_KVSSD_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "core/db_factory.h"
+#include "kvssd_const.h"
+
+namespace kvssd {
+
+enum class kvs_result {
+    KVS_SUCCESS = 0,                // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,   // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,  // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,  // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,    // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,       // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,       // index is not valid
+    KVS_ERR_KS_NAME = 0x007,        // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,   // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,    // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,        // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID =
+        0x00B,                           // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,        // the maximum number of iterators that a
+                                         // device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,  // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,       // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,  // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,       // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,      // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,       // null input parameter
+    KVS_ERR_SYS_IO = 0x013,              // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,  // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,  // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED =
+        0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017,  // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,            // device was not opened yet
+};
+
+inline const char *kvstrerror[] =  // kvs_result을 Index, 대응되는 에러문을
+                                   // Value로 갖는 배열 = {
path: kvssd/kvssd.h
user: login: BlaCkinkGJ
body: 영어로 변환 부탁드립니다!
created_at: 2025-04-27T00:33:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+#ifndef YCSB_C_KVSSD_H_
+#define YCSB_C_KVSSD_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "core/db_factory.h"
+#include "kvssd_const.h"
+
+namespace kvssd {
+
+enum class kvs_result {
+    KVS_SUCCESS = 0,                // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,   // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,  // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,  // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,    // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,       // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,       // index is not valid
+    KVS_ERR_KS_NAME = 0x007,        // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,   // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,    // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,        // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID =
+        0x00B,                           // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,        // the maximum number of iterators that a
+                                         // device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,  // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,       // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,  // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,       // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,      // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,       // null input parameter
+    KVS_ERR_SYS_IO = 0x013,              // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,  // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,  // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED =
+        0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017,  // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,            // device was not opened yet
+};
+
+inline const char *kvstrerror[] =  // kvs_result을 Index, 대응되는 에러문을
+                                   // Value로 갖는 배열 = {
+    {
+        "Successful",                            // KVS_SUCCESS
+        "Buffer space is not enough",            // KVS_ERR_BUFFER_SMALL
+        "Device does not have enough space",     // KVS_ERR_DEV_CAPAPCITY
+        "No device with the dev_hd exists",      // KVS_ERR_DEV_NOT_EXIST
+        "Key space does not have enough space",  // KVS_ERR_KS_CAPACITY
+        "Key space is already created",          // KVS_ERR_KS_EXIST
+        "Index is not valid",                    // KVS_ERR_KS_INDEX
+        "Key space name is not valid",           // KVS_ERR_KS_NAME
+        "Key space does not exist",              // KVS_ERR_KS_NOT_EXIST
+        "Key space does not open",               // KVS_ERR_KS_NOT_OPEN
+        "Key space is already opened",           // KVS_ERR_KS_OPEN
+        "Iterator filter is not valid",          // KVS_ERR_ITERATOR_FILTER_INVALID
+        "Maximum number of iterators opened",    // KVS_ERR_ITERATOR_MAX
+        "Iterator Key Group does not exist",     // KVS_ERR_ITERATOR_NOT_EXIST
+        "Iterator is already opened",            // KVS_ERR_ITERATOR_OPEN
+        "Key is not valid",                      // KVS_ERR_KEY_LENGTH_INVALID
+        "Key does not exist",                    // KVS_ERR_KEY_NOT_EXIST
+        "Option is not supported",               // KVS_ERR_OPTION_INVALID
+        "Null input parameter",                  // KVS_ERR_PARAM_INVALID
+        "I/O error occurs",                      // KVS_ERR_SYS_IO
+        "Value length is out of range",          // KVS_ERR_VALUE_LENGTH_INVALID
+        "Value offset is out of range",          // KVS_ERR_VALUE_OFFSET_INVALID
+        "Value offset is misaligned",            // KVS_ERR_VALUE_OFFSET_MISALIGNED
+        "Value update is not allowed",           // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+        "Device was not opened yet"              // KVS_ERR_DEV_NOT_OPENED
+};
+
+struct kvs_key {
+    void *key;
+    uint16_t length;
+
+    bool operator==(const kvs_key &other) const {
+        return length == other.length && std::memcmp(key, other.key, length) == 0;
+    }
+};
+
+struct kvs_value {
+    void *value;                 // value byte stream 버퍼의 시작 주소
+    uint32_t length;             // value byte stream 버퍼의 크기 (단위: byte)
+    uint32_t actual_value_size;  // device에 저장된 value의 실제 크기 (단위: byte)
+    uint32_t offset;             // [optional] device에 저장된 value의 offset (단위: byte)
path: kvssd/kvssd.h
user: login: BlaCkinkGJ
body: 영어로 변환 부탁드립니다!
created_at: 2025-04-27T00:33:45Z
author_association: COLLABORATOR
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: 나중에 기회가 되면 Test Coverage를 측정하는 것을 해보는 것도 좋을 것 같네요!
created_at: 2025-04-27T00:35:32Z
author_association: COLLABORATOR
path: result.load
user: login: BlaCkinkGJ
body: 제가 까먹어서 그러는데, 혹시 이 파일의 용도는 뭘까요?
created_at: 2025-04-27T00:35:50Z
author_association: COLLABORATOR
diff_hunk: @@ -264,12 +264,7 @@ void ParseCommandLine(int argc, const char *argv[], ycsbc::utils::Properties &pr
       }
       std::string filename(argv[argindex]);
       std::ifstream input(argv[argindex]);
-      try {
-        props.Load(input);
-      } catch (const std::string &message) {
-        std::cerr << message << std::endl;
-        exit(0);
-      }
+      props.Load(input);
path: core/ycsbc.cc
user: login: easter423
body: fix(kvssd): Debugging PR (https://github.com/veritross/YCSB-cpp/issues/1)
해당 PR에서 디버깅 중에 삭제된 것 같습니다. 해당 코드는 다시 돌려놓겠습니다.
created_at: 2025-04-27T02:51:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.10)
+project(hashmap-kvssd)
+set(CMAKE_CXX_STANDARD 17)
+enable_testing()
+
+set(CMAKE_BUILD_TYPE Release)
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        )
+        
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g")
+        
+set(TARGET_APP kvssd_test)
+set(SrcLib SrcLib)
+set(SrcFiles kvssd_hashmap_db_impl.cc kvssd_hashmap_db.cc kvssd.cc)
+
+add_library(${SrcLib} STATIC ${SrcFiles})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+add_subdirectory(googletest-1.15.2)
+add_executable(${TARGET_APP} test/kvssd_test.cc)
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+target_link_libraries(${TARGET_APP} gtest_main ${SrcLib})
+
+include(GoogleTest)
+gtest_discover_tests(${TARGET_APP})
+
+# Valgrind memcheck 설정 및 테스트 등록
path: kvssd/CMakeLists.txt
user: login: easter423
body: 주석 삭제하였습니다. 한국어 삭제 관련하여 전체적으로 탐색했다고 생각했는데, 계속 놓치는 부분이 있네요😅 혹시 따로 찾는 도구가 있을까요?
created_at: 2025-04-27T02:51:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,56 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    if (backend == "kvssd") {
+        // TODO: ret = new kvssd::KVSSD();
+    }
path: kvssd/kvssd.cc
user: login: easter423
body: VSCode IDE에 SonarQube 세팅 완료하였습니다! 해당 툴로 분석 결과 수정할 부분이 너무 많아서(71개) 해당 부분은 다른 commit에서 별도로 처리하겠습니다.
created_at: 2025-04-27T02:51:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+#ifndef YCSB_C_KVSSD_H_
+#define YCSB_C_KVSSD_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "core/db_factory.h"
+#include "kvssd_const.h"
+
+namespace kvssd {
+
+enum class kvs_result {
+    KVS_SUCCESS = 0,                // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,   // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,  // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,  // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,    // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,       // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,       // index is not valid
+    KVS_ERR_KS_NAME = 0x007,        // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,   // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,    // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,        // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID =
+        0x00B,                           // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,        // the maximum number of iterators that a
+                                         // device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,  // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,       // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,  // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,       // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,      // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,       // null input parameter
+    KVS_ERR_SYS_IO = 0x013,              // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,  // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,  // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED =
+        0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017,  // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,            // device was not opened yet
+};
+
+inline const char *kvstrerror[] =  // kvs_result을 Index, 대응되는 에러문을
+                                   // Value로 갖는 배열 = {
path: kvssd/kvssd.h
user: login: easter423
body: 변환하였습니다.
created_at: 2025-04-27T02:51:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+#ifndef YCSB_C_KVSSD_H_
+#define YCSB_C_KVSSD_H_
+
+#include <pthread.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+#include "core/db_factory.h"
+#include "kvssd_const.h"
+
+namespace kvssd {
+
+enum class kvs_result {
+    KVS_SUCCESS = 0,                // Successful
+    KVS_ERR_BUFFER_SMALL = 0x001,   // buffer space is not enough
+    KVS_ERR_DEV_CAPAPCITY = 0x002,  // device does not have enough space. Key Space size is too big
+    KVS_ERR_DEV_NOT_EXIST = 0x003,  // no device with the dev_hd exists
+    KVS_ERR_KS_CAPACITY = 0x004,    // key space does not have enough space
+    KVS_ERR_KS_EXIST = 0x005,       // key space is already created with the same name
+    KVS_ERR_KS_INDEX = 0x006,       // index is not valid
+    KVS_ERR_KS_NAME = 0x007,        // key space name is not valid
+    KVS_ERR_KS_NOT_EXIST = 0x008,   // key space does not exist
+    KVS_ERR_KS_NOT_OPEN = 0x009,    // key space does not open
+    KVS_ERR_KS_OPEN = 0x00A,        // key space is already opened
+    KVS_ERR_ITERATOR_FILTER_INVALID =
+        0x00B,                           // iterator filter(match bitmask and pattern) is not valid
+    KVS_ERR_ITERATOR_MAX = 0x00C,        // the maximum number of iterators that a
+                                         // device supports is opened
+    KVS_ERR_ITERATOR_NOT_EXIST = 0x00D,  // the iterator Key Group does not exist
+    KVS_ERR_ITERATOR_OPEN = 0x00E,       // iterator is already opened
+    KVS_ERR_KEY_LENGTH_INVALID = 0x00F,  // key is not valid (e.g., key length is not supported)
+    KVS_ERR_KEY_NOT_EXIST = 0x010,       // key does not exist
+    KVS_ERR_OPTION_INVALID = 0x011,      // an option is not supported in this implementation
+    KVS_ERR_PARAM_INVALID = 0x012,       // null input parameter
+    KVS_ERR_SYS_IO = 0x013,              // I/O error occurs
+    KVS_ERR_VALUE_LENGTH_INVALID = 0x014,  // value length is out of range
+    KVS_ERR_VALUE_OFFSET_INVALID = 0x015,  // value offset is out of range
+    KVS_ERR_VALUE_OFFSET_MISALIGNED =
+        0x016,  // offset of value is required to be aligned to KVS_ALIGNMENT_UNIT
+    KVS_ERR_VALUE_UPDATE_NOT_ALLOWED = 0x017,  // key exists but value update is not allowed
+    KVS_ERR_DEV_NOT_OPENED = 0x018,            // device was not opened yet
+};
+
+inline const char *kvstrerror[] =  // kvs_result을 Index, 대응되는 에러문을
+                                   // Value로 갖는 배열 = {
+    {
+        "Successful",                            // KVS_SUCCESS
+        "Buffer space is not enough",            // KVS_ERR_BUFFER_SMALL
+        "Device does not have enough space",     // KVS_ERR_DEV_CAPAPCITY
+        "No device with the dev_hd exists",      // KVS_ERR_DEV_NOT_EXIST
+        "Key space does not have enough space",  // KVS_ERR_KS_CAPACITY
+        "Key space is already created",          // KVS_ERR_KS_EXIST
+        "Index is not valid",                    // KVS_ERR_KS_INDEX
+        "Key space name is not valid",           // KVS_ERR_KS_NAME
+        "Key space does not exist",              // KVS_ERR_KS_NOT_EXIST
+        "Key space does not open",               // KVS_ERR_KS_NOT_OPEN
+        "Key space is already opened",           // KVS_ERR_KS_OPEN
+        "Iterator filter is not valid",          // KVS_ERR_ITERATOR_FILTER_INVALID
+        "Maximum number of iterators opened",    // KVS_ERR_ITERATOR_MAX
+        "Iterator Key Group does not exist",     // KVS_ERR_ITERATOR_NOT_EXIST
+        "Iterator is already opened",            // KVS_ERR_ITERATOR_OPEN
+        "Key is not valid",                      // KVS_ERR_KEY_LENGTH_INVALID
+        "Key does not exist",                    // KVS_ERR_KEY_NOT_EXIST
+        "Option is not supported",               // KVS_ERR_OPTION_INVALID
+        "Null input parameter",                  // KVS_ERR_PARAM_INVALID
+        "I/O error occurs",                      // KVS_ERR_SYS_IO
+        "Value length is out of range",          // KVS_ERR_VALUE_LENGTH_INVALID
+        "Value offset is out of range",          // KVS_ERR_VALUE_OFFSET_INVALID
+        "Value offset is misaligned",            // KVS_ERR_VALUE_OFFSET_MISALIGNED
+        "Value update is not allowed",           // KVS_ERR_VALUE_UPDATE_NOT_ALLOWED
+        "Device was not opened yet"              // KVS_ERR_DEV_NOT_OPENED
+};
+
+struct kvs_key {
+    void *key;
+    uint16_t length;
+
+    bool operator==(const kvs_key &other) const {
+        return length == other.length && std::memcmp(key, other.key, length) == 0;
+    }
+};
+
+struct kvs_value {
+    void *value;                 // value byte stream 버퍼의 시작 주소
+    uint32_t length;             // value byte stream 버퍼의 크기 (단위: byte)
+    uint32_t actual_value_size;  // device에 저장된 value의 실제 크기 (단위: byte)
+    uint32_t offset;             // [optional] device에 저장된 value의 offset (단위: byte)
path: kvssd/kvssd.h
user: login: easter423
body: 변환하였습니다!
created_at: 2025-04-27T02:52:02Z
author_association: COLLABORATOR
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 넵! 추천하시는 test coverage tool이 있으실까요?
created_at: 2025-04-27T02:52:05Z
author_association: COLLABORATOR
path: result.load
user: login: easter423
body: 용도는 따로 없습니다. 해당 파일은 직접 삭제하였습니다.
created_at: 2025-04-27T02:52:08Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,56 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    if (backend == "kvssd") {
+        // TODO: ret = new kvssd::KVSSD();
+    }
path: kvssd/kvssd.cc
user: login: easter423
body: 해당 50~52 줄에 대해서는 SonarQube가 if문 내부에 아무 명령줄이 없는 경우 issue를 표기하지만, 따로 주석으로 명시한 경우 문제가 없는 것으로 판단하는 것 같습니다. 다만 말씀주신대로 불필요한 어셈블리가 생성될 것 같아 해당 부분은 전부 주석처리하겠습니다.
created_at: 2025-04-27T03:03:25Z
author_association: COLLABORATOR
path: kvssd/test/kvssd_test.cc
user: login: BlaCkinkGJ
body: gcc에 동봉된 gcov를 저는 개인적으로 추천해요. https://int-i.github.io/cpp/2021-08-14/cpp-codecov/

근데 coverage 높이는 것은 다음으로 하시죠!!
created_at: 2025-04-27T03:21:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.10)
+project(hashmap-kvssd)
+set(CMAKE_CXX_STANDARD 17)
+enable_testing()
+
+set(CMAKE_BUILD_TYPE Release)
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        )
+        
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g")
+        
+set(TARGET_APP kvssd_test)
+set(SrcLib SrcLib)
+set(SrcFiles kvssd_hashmap_db_impl.cc kvssd_hashmap_db.cc kvssd.cc)
+
+add_library(${SrcLib} STATIC ${SrcFiles})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+add_subdirectory(googletest-1.15.2)
+add_executable(${TARGET_APP} test/kvssd_test.cc)
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+target_link_libraries(${TARGET_APP} gtest_main ${SrcLib})
+
+include(GoogleTest)
+gtest_discover_tests(${TARGET_APP})
+
+# Valgrind memcheck 설정 및 테스트 등록
path: kvssd/CMakeLists.txt
user: login: BlaCkinkGJ
body: 아뇨, 눈으로 보는거죠 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 그래서 PR을 완성하고 나서 저도 몇 번을 다시 봅니다. 그래도 저도 아직까지 놓치는게 많아요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
created_at: 2025-04-27T03:22:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,56 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    if (backend == "kvssd") {
+        // TODO: ret = new kvssd::KVSSD();
+    }
path: kvssd/kvssd.cc
user: login: BlaCkinkGJ
body: 넵, 주석 처리 완료되면 approve 하도록 하겠습니다!
created_at: 2025-04-27T03:23:19Z
author_association: COLLABORATOR
path: kvssd/test/kvssd_test.cc
user: login: easter423
body: 네 알겠습니다 :)
created_at: 2025-04-27T03:53:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,56 @@
+#include "kvssd.h"
+
+#include "kvssd_hashmap_db.h"
+#include "kvssd_hashmap_db_impl.h"
+
+namespace {
+const std::string PROP_BACKEND = "hashmap";
+}  // anonymous namespace
+
+class KvssdDbWrapper : public ycsbc::DB {
+   private:
+    std::unique_ptr<kvssd::KVSSD> kvssd;
+
+   public:
+    KvssdDbWrapper(kvssd::KVSSD *k) : kvssd(k) {};
+    ycsbc::DB::Status Read(const std::string &table, const std::string &key,
+                           const std::vector<std::string> *fields,
+                           std::vector<ycsbc::DB::Field> &result) {
+        kvssd_hashmap::ReadRow(this->kvssd, key, result);
+        return kOK;
+    }
+    ycsbc::DB::Status Scan(const std::string &table, const std::string &key, int len,
+                           const std::vector<std::string> *fields,
+                           std::vector<std::vector<ycsbc::DB::Field>> &result) {
+        return kNotImplemented;
+    }
+    ycsbc::DB::Status Update(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::UpdateRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Insert(const std::string &table, const std::string &key,
+                             std::vector<ycsbc::DB::Field> &values) {
+        kvssd_hashmap::InsertRow(this->kvssd, key, values);
+        return kOK;
+    }
+    ycsbc::DB::Status Delete(const std::string &table, const std::string &key) {
+        kvssd_hashmap::DeleteRow(this->kvssd, key);
+        return kOK;
+    }
+};
+
+ycsbc::DB *NewKvssdDB() {
+    std::string backend = PROP_BACKEND;
+    ycsbc::DB *ret = nullptr;
+    if (backend == "hashmap") {
+        kvssd::KVSSD *k = new kvssd_hashmap::Hashmap_KVSSD();
+        ret = new KvssdDbWrapper(k);
+    }
+    if (backend == "kvssd") {
+        // TODO: ret = new kvssd::KVSSD();
+    }
path: kvssd/kvssd.cc
user: login: easter423
body: 주석 처리 완료하였습니다. 
SonarQube 관련 수정사항은 추후 진행하도록 하겠습니다.
created_at: 2025-04-27T04:05:18Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,134 @@
+#include "kvssd_hashmap_db_impl.h"
+
+#include <cstdio>
+#include <iostream>
+
+namespace kvssd_hashmap {
+
+// Field vector to string pointer
+void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data) {
+    for (const ycsbc::DB::Field &field : values) {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+// char* to Field vector pointer
+void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len) {
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim) {
+        assert(p < lim);
+        uint32_t vlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(vlen));
+        p += vlen;
+        uint32_t tlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(tlen));
+        p += tlen;
+        values->push_back({field, value});
+    }
+}
+
+std::unique_ptr<kvs_row, KvsRowDeleter> CreateRow(const std::string &key_in,
+                                                  const std::vector<ycsbc::DB::Field> &value_in) {
+    uint16_t key_length = key_in.size();
+    void *key = malloc(key_length);
+    std::memcpy(key, (void *)(key_in.data()), key_length);
+
+    void *value = nullptr;
+    std::string value_sz;
+    uint32_t value_length = 0;
+    uint32_t actual_value_size = 0;
+    uint32_t offset = 0;
+    if (!value_in.empty()) {
+        SerializeRow(value_in, &value_sz);
+        value = malloc(value_sz.size());
+        std::memcpy(value, value_sz.data(), value_sz.size());
+        value_length = value_sz.size();
+        actual_value_size = value_sz.size();
+        offset = 0;
+    }
+
+    kvssd::kvs_key *newKey = new kvssd::kvs_key;
+    newKey->key = key;
+    newKey->length = key_length;
+    kvssd::kvs_value *newValue = new kvssd::kvs_value;
+    newValue->value = value;
+    newValue->length = value_length;
+    newValue->actual_value_size = actual_value_size;
+    newValue->offset = offset;
+
+    kvs_row *newRow = new kvs_row;
+    newRow->key = newKey;
+    newRow->value = newValue;
+
+    return std::unique_ptr<kvs_row, KvsRowDeleter>(newRow);
+}
+
+// Print kvs_value
+void PrintRow(const kvssd::kvs_value &value) {
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: easter423
body: PrintRow와 PrintFieldVector 함수는 특정 key-value 값이 무엇인지 출력하는 디버깅 함수입니다. 실제 동작 시에는 사용하지 않는데, 지우는게 나을까요?
created_at: 2025-04-27T04:57:32Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.10)
+project(hashmap-kvssd)
+set(CMAKE_CXX_STANDARD 17)
+enable_testing()
+
+set(CMAKE_BUILD_TYPE Release)
+set(CompilerFlags
+        CMAKE_CXX_FLAGS
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        )
+        
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g")
+        
+set(TARGET_APP kvssd_test)
+set(SrcLib SrcLib)
+set(SrcFiles kvssd_hashmap_db_impl.cc kvssd_hashmap_db.cc kvssd.cc)
+
+add_library(${SrcLib} STATIC ${SrcFiles})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${SrcLib} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+add_subdirectory(googletest-1.15.2)
+add_executable(${TARGET_APP} test/kvssd_test.cc)
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR})
+target_include_directories(${TARGET_APP} PUBLIC ${CMAKE_SOURCE_DIR}/../)
+target_link_libraries(${TARGET_APP} gtest_main ${SrcLib})
+
+include(GoogleTest)
+gtest_discover_tests(${TARGET_APP})
+
+# Valgrind memcheck 설정 및 테스트 등록
path: kvssd/CMakeLists.txt
user: login: easter423
body: 으악.... 눈썰미를 길러야겠군요ㅜㅜ
created_at: 2025-04-27T04:58:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,134 @@
+#include "kvssd_hashmap_db_impl.h"
+
+#include <cstdio>
+#include <iostream>
+
+namespace kvssd_hashmap {
+
+// Field vector to string pointer
+void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data) {
+    for (const ycsbc::DB::Field &field : values) {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+// char* to Field vector pointer
+void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len) {
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim) {
+        assert(p < lim);
+        uint32_t vlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(vlen));
+        p += vlen;
+        uint32_t tlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(tlen));
+        p += tlen;
+        values->push_back({field, value});
+    }
+}
+
+std::unique_ptr<kvs_row, KvsRowDeleter> CreateRow(const std::string &key_in,
+                                                  const std::vector<ycsbc::DB::Field> &value_in) {
+    uint16_t key_length = key_in.size();
+    void *key = malloc(key_length);
+    std::memcpy(key, (void *)(key_in.data()), key_length);
+
+    void *value = nullptr;
+    std::string value_sz;
+    uint32_t value_length = 0;
+    uint32_t actual_value_size = 0;
+    uint32_t offset = 0;
+    if (!value_in.empty()) {
+        SerializeRow(value_in, &value_sz);
+        value = malloc(value_sz.size());
+        std::memcpy(value, value_sz.data(), value_sz.size());
+        value_length = value_sz.size();
+        actual_value_size = value_sz.size();
+        offset = 0;
+    }
+
+    kvssd::kvs_key *newKey = new kvssd::kvs_key;
+    newKey->key = key;
+    newKey->length = key_length;
+    kvssd::kvs_value *newValue = new kvssd::kvs_value;
+    newValue->value = value;
+    newValue->length = value_length;
+    newValue->actual_value_size = actual_value_size;
+    newValue->offset = offset;
+
+    kvs_row *newRow = new kvs_row;
+    newRow->key = newKey;
+    newRow->value = newValue;
+
+    return std::unique_ptr<kvs_row, KvsRowDeleter>(newRow);
+}
+
+// Print kvs_value
+void PrintRow(const kvssd::kvs_value &value) {
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: BlaCkinkGJ
body: 이런 건 디버깅에 유용하니 `#ifdef`로 처리하도록 하시죠! `#ifdef DEBUG` 로 DEBUG가 활성화된 상황에서만 동작하게 하는거죠.
created_at: 2025-04-27T05:02:08Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,134 @@
+#include "kvssd_hashmap_db_impl.h"
+
+#include <cstdio>
+#include <iostream>
+
+namespace kvssd_hashmap {
+
+// Field vector to string pointer
+void SerializeRow(const std::vector<ycsbc::DB::Field> &values, std::string *data) {
+    for (const ycsbc::DB::Field &field : values) {
+        uint32_t len = field.name.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.name.data(), field.name.size());
+        len = field.value.size();
+        data->append(reinterpret_cast<char *>(&len), sizeof(uint32_t));
+        data->append(field.value.data(), field.value.size());
+    }
+}
+
+// char* to Field vector pointer
+void DeserializeRow(std::vector<ycsbc::DB::Field> *values, const char *data_ptr, size_t data_len) {
+    const char *p = data_ptr;
+    const char *lim = p + data_len;
+    while (p != lim) {
+        assert(p < lim);
+        uint32_t vlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string field(p, static_cast<const size_t>(vlen));
+        p += vlen;
+        uint32_t tlen = *reinterpret_cast<const uint32_t *>(p);
+        p += sizeof(uint32_t);
+        std::string value(p, static_cast<const size_t>(tlen));
+        p += tlen;
+        values->push_back({field, value});
+    }
+}
+
+std::unique_ptr<kvs_row, KvsRowDeleter> CreateRow(const std::string &key_in,
+                                                  const std::vector<ycsbc::DB::Field> &value_in) {
+    uint16_t key_length = key_in.size();
+    void *key = malloc(key_length);
+    std::memcpy(key, (void *)(key_in.data()), key_length);
+
+    void *value = nullptr;
+    std::string value_sz;
+    uint32_t value_length = 0;
+    uint32_t actual_value_size = 0;
+    uint32_t offset = 0;
+    if (!value_in.empty()) {
+        SerializeRow(value_in, &value_sz);
+        value = malloc(value_sz.size());
+        std::memcpy(value, value_sz.data(), value_sz.size());
+        value_length = value_sz.size();
+        actual_value_size = value_sz.size();
+        offset = 0;
+    }
+
+    kvssd::kvs_key *newKey = new kvssd::kvs_key;
+    newKey->key = key;
+    newKey->length = key_length;
+    kvssd::kvs_value *newValue = new kvssd::kvs_value;
+    newValue->value = value;
+    newValue->length = value_length;
+    newValue->actual_value_size = actual_value_size;
+    newValue->offset = offset;
+
+    kvs_row *newRow = new kvs_row;
+    newRow->key = newKey;
+    newRow->value = newValue;
+
+    return std::unique_ptr<kvs_row, KvsRowDeleter>(newRow);
+}
+
+// Print kvs_value
+void PrintRow(const kvssd::kvs_value &value) {
path: kvssd/kvssd_hashmap_db_impl.cc
user: login: easter423
body: 그런 방법이 있었군요..! 해당 작업까지 진행하겠습니다.
created_at: 2025-04-27T05:04:06Z
author_association: COLLABORATOR

PR comments:
user: login: BlaCkinkGJ
created_at: 2024-12-05T13:12:06Z
body: 혹시 formatter 뭐 사용하시나요? (e.g., [clang-format](https://nx006.tistory.com/62))

추가로 아직 resolved 처리가 되지 않은 내용들은 처리가 완료되어야 한다는 의미예요 🙂 
author_association: COLLABORATOR
user: login: easter423
created_at: 2024-12-05T14:03:46Z
body: > 혹시 formatter 뭐 사용하시나요? (e.g., [clang-format](https://nx006.tistory.com/62))
> 
> 추가로 아직 resolved 처리가 되지 않은 내용들은 처리가 완료되어야 한다는 의미예요 🙂

현재 vscode 확장 프로그램으로 ms-vscode.cpptools 를 사용하고 이는 내부적으로 clang-format 포맷터를 사용한다고 하는데, 세부적으로 어떤 스타일로 지정할지는 Clang-Format 확장 프로그램을 따로 깔아야 하는 것으로 보여요

+ 혹시 추천해 주실만한 formatter가 따로 있으신가요?
author_association: COLLABORATOR
user: login: easter423
created_at: 2024-12-05T14:24:44Z
body: > main 브랜치에서 pull을 받아서 업데이트 하는 것이 좋을 것 같아요. :) 그리고 추가로 생각나서 올립니다 ㅠㅠㅠ 일전에 리뷰할 때 한꺼번에 해드려야했는데 미처놓쳤네요.....

제 저장소의 main 브랜치에서는 pull 받을 내용이 없다고 나오는데 혹시 어떤 main 브랜치에서 pull을 받아야 하는지 알려주실 수 있으신가요?? 😅
author_association: COLLABORATOR
user: login: BlaCkinkGJ
created_at: 2024-12-06T04:41:27Z
body: > 제 저장소의 main 브랜치에서는 pull 받을 내용이 없다고 나오는데 혹시 어떤 main 브랜치에서 pull을 받아야 하는지 알려주실 수 있으신가요?? 😅

현재 개발용 브랜치 이름이 main이 아니라 master(구 git의 개발용 브랜치)이군요.. `git remote set-url upstream https://github.com/veritross/YCSB-cpp.git` 한 후에 `git pull upstream master`를 해주시면 됩니다.
author_association: COLLABORATOR
user: login: BlaCkinkGJ
created_at: 2024-12-06T04:42:56Z
body: > 현재 vscode 확장 프로그램으로 ms-vscode.cpptools 를 사용하고 이는 내부적으로 clang-format 포맷터를 사용한다고 하는데, 세부적으로 어떤 스타일로 지정할지는 Clang-Format 확장 프로그램을 따로 깔아야 하는 것으로 보여요
>
> 혹시 추천해 주실만한 formatter가 따로 있으신가요?

vscode의 formatter가 동작 중이라면 상관없는 것 같은데... 몇몇 부분은 formatter가 동작하지 않은 듯하게 보이는 부분이 있어보여서요.

저도 일반적으로는 clang-format을 사용합니다. 이번 브랜치 병합하고 적당한 포맷 규칙을 정해봐야겠군요.
author_association: COLLABORATOR
user: login: easter423
created_at: 2024-12-06T15:07:11Z
body: > > 제 저장소의 main 브랜치에서는 pull 받을 내용이 없다고 나오는데 혹시 어떤 main 브랜치에서 pull을 받아야 하는지 알려주실 수 있으신가요?? 😅
> 
> 현재 개발용 브랜치 이름이 main이 아니라 master(구 git의 개발용 브랜치)이군요.. `git remote set-url upstream https://github.com/veritross/YCSB-cpp.git` 한 후에 `git pull upstream master`를 해주시면 됩니다.

아래 작업을 통해 제 원격 repo 업데이트 완료하였습니다.
```
git remote add upstream https://github.com/veritross/YCSB-cpp.git
git fetch upstream master
git rebase upstream/master
git push --force-with-lease
```
author_association: COLLABORATOR
user: login: BlaCkinkGJ
created_at: 2024-12-16T15:21:24Z
body: 조금만 더 고치면 바로 LGTM 날릴 수 있도록 하겠습니다!!
author_association: COLLABORATOR
user: login: easter423
created_at: 2025-02-04T17:50:55Z
body: ycsb test 중 load 이후 run 과정에서 Read나 Update 수행 시 해당 key를 찾을 수 없다는 에러가 발생하여, 원인을 찾았습니다.

현재 ycsb에서는 load와 run을 통해 test를 진행할 수 있는데, load 수행 시 정해진 개수만큼의 insert를 반복 수행하여 db에 저장하고, 저장한 정보를 /tmp/(명시된 경로) 에 data.mdb(lmdb의 경우) 등의 형태로 저장합니다. 이후 run 수행 시 해당 파일에 저장된 정보를 가진 db를 생성하고, 여러 API를 사용하여 test를 진행합니다.

하지만 제가 작성한 hashmap 코드의 경우 정보를 따로 특정 위치에 저장하거나 복구하는 장치가 없어서 현재 코드로는 위 방식대로 테스트가 어려울 것 같습니다.

https://gist.github.com/easter423/a5e4bc96b569df2859817cff09537ad4 의 마지막 comment에도 게시한 내용입니다.
author_association: COLLABORATOR
user: login: easter423
created_at: 2025-04-09T11:50:40Z
body: [Gist](https://gist.github.com/easter423/4821e4db8f7edc1e7e0af4b63c5a2020)와 [Notion](https://www.notion.so/Hashmap_KVSSD-04-09-1d0d07017c0f800ca87ce430d78e3588)에 다음 commit에서의 변경 사항 내용을 정리하였습니다:
- [fix(kvssd): resolved heap Read After Free and memory leak problems](https://github.com/veritross/YCSB-cpp/pull/5/commits/70495095e5b0ddf3b4184f2a271171242fe71082)
author_association: COLLABORATOR
user: login: BlaCkinkGJ
created_at: 2025-04-09T13:01:15Z
body: https://github.com/analysis-tools-dev/static-analysis?tab=readme-ov-file#cpp
author_association: COLLABORATOR
user: login: easter423
created_at: 2025-04-26T04:12:20Z
body: 다음 사항을 수정하였습니다:

- 한글 주석 영문으로 변환
- dictionary 자료구조 free 방식 변경 (각 원소 별 free 후 전체 db.clear() 방식으로 변경)
- TODO 표기법 추가
- CreateRow() 함수에서 allocate_value 매개변수 삭제, value_in vector가 비어있는 지 확인하는 방식으로 대체

다음 [static-analysis](https://github.com/analysis-tools-dev/static-analysis) tools를 사용하여 검증 완료하였습니다. 따로 발견된 문제는 없어 수정 사항은 없습니다.

- https://github.com/danmar/cppcheck
- https://github.com/terryyin/lizard

현재 C++ format style은 [google](https://google.github.io/styleguide/cppguide.html)입니다.
author_association: COLLABORATOR
user: login: BlaCkinkGJ
created_at: 2025-04-27T05:04:09Z
body: 참고로 Squash and merge 부탁드릴게요!!
author_association: COLLABORATOR