From 4debf62971ce6d60f7610820c370ae49866d4c2e Mon Sep 17 00:00:00 2001 From: ened Date: Thu, 8 Jun 2023 08:54:54 +0900 Subject: [PATCH] Working query functions --- KissMeme/KissDB.swift | 38 +++++--- KissMemeTests/KissMemeTests.swift | 147 ++++++++++++++++++++++++------ kiss-db/kiss-db/kiss-db.c | 66 ++++++++++---- kiss-db/kiss-db/kiss-db.h | 9 +- 4 files changed, 195 insertions(+), 65 deletions(-) diff --git a/KissMeme/KissDB.swift b/KissMeme/KissDB.swift index ac1b8fc..e142020 100644 --- a/KissMeme/KissDB.swift +++ b/KissMeme/KissDB.swift @@ -80,7 +80,7 @@ public class KissDB: NSObject { let value = CString(item.value) cItem.pointee.key = UnsafeMutableRawPointer(key.mutableString) - cItem.pointee.key_size = UInt32(key.size) + cItem.pointee.key_size = UInt64(key.size) cItem.pointee.data = UnsafeMutableRawPointer(key.mutableString) cItem.pointee.data_size = UInt64(value.size) @@ -89,39 +89,47 @@ public class KissDB: NSObject { } } - public func insertBulk(from: ((Item)->Bool)?) throws { + public func insert(from: ((Item)->Bool)?) throws { let obj = CallbackObject(itemCallback: from) let userPtr = Unmanaged.passUnretained(obj).toOpaque() - guard kiss_db_insert_bulk(cPtr, true, CallbackObject.insertCallback, userPtr, cError) else { + guard kiss_db_insert_from(cPtr, true, CallbackObject.insertCallback, userPtr, cError) else { throw KissDBError.general(cError.code, cError.message) } } - public func delete(key: String, output: ((Item)->Bool)?) throws { + public func delete(key: String) throws { let key = CString(key) - let obj = CallbackObject(itemCallback: output) + guard kiss_db_delete(cPtr, key.mutableString, UInt32(key.size), cError) else { + throw KissDBError.general(cError.code, cError.message) + } + } + + public func delete(key: String, into: ((Item)->Bool)?) throws { + let key = CString(key) + + let obj = CallbackObject(itemCallback: into) let userPtr = Unmanaged.passUnretained(obj).toOpaque() - guard kiss_db_delete(cPtr, key.mutableString, UInt32(key.size), CallbackObject.deleteCallback, userPtr, cError) else { + guard kiss_db_delete_into(cPtr, key.mutableString, UInt32(key.size), CallbackObject.deleteCallback, userPtr, cError) else { throw KissDBError.general(cError.code, cError.message) } } - public func select(key: String, output: ((Item)->Bool)?) throws { + public func select(key: String, into: ((Item)->Bool)?) throws { let key = CString(key) - let obj = CallbackObject(itemCallback: output) + let obj = CallbackObject(itemCallback: into) let userPtr = Unmanaged.passUnretained(obj).toOpaque() guard kiss_db_select(cPtr, key.mutableString, UInt32(key.size), CallbackObject.selectCallback, userPtr, cError) else { throw KissDBError.general(cError.code, cError.message) } } - public func selectAll(output: ((Item)->Bool)?) throws { - let obj = CallbackObject(itemCallback: output) + public func select(into: ((Item)->Bool)?) throws { + let obj = CallbackObject(itemCallback: into) let userPtr = Unmanaged.passUnretained(obj).toOpaque() - guard kiss_db_select_bulk(cPtr, CallbackObject.selectCallback, userPtr, cError) else { + guard kiss_db_select_all(cPtr, CallbackObject.selectCallback, userPtr, cError) else { throw KissDBError.general(cError.code, cError.message) } } @@ -139,12 +147,18 @@ class CallbackObject: NSObject { static let insertCallback: kiss_insert_callback = { (item: UnsafeMutablePointer?, userPtr: UnsafeMutableRawPointer?) -> kiss_bool in let obj = Unmanaged.fromOpaque(userPtr!).takeUnretainedValue() if let itemCallback = obj.itemCallback, let item = item { + KissDB.Item(key: , value: <#T##String#>) + + if itemCallback(item) { + item.pointee.key = item.pointee.key.bindMemory(to: CChar.self, capacity: Int(item.pointee.key_size)) + item.pointee.key_size = item.po + item.pointee.data = item.pointee.data.bindMemory(to: CChar.self, capacity: Int(item.pointee.data_size)) + } let cKey = item.pointee.key.bindMemory(to: CChar.self, capacity: Int(item.pointee.key_size)) let cValue = item.pointee.data.bindMemory(to: CChar.self, capacity: Int(item.pointee.data_size)) let key = String(cString: cKey) let value = String(cString: cValue) let item = KissDB.Item(key: key, value: value) - return itemCallback(item) } // Continue to insert remained items return true diff --git a/KissMemeTests/KissMemeTests.swift b/KissMemeTests/KissMemeTests.swift index 21a64d1..5cbf704 100644 --- a/KissMemeTests/KissMemeTests.swift +++ b/KissMemeTests/KissMemeTests.swift @@ -10,14 +10,123 @@ import KissMeme final class KissMemeTests: XCTestCase { + var testDBDirectory: URL! + override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. + + let directory = URL.currentDirectory().appending(path: "testdb") + try? FileManager.default.removeItem(at: directory) + try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + print(directory.path) + testDBDirectory = directory } override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } + + + private func testInsert(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + + for i in 0 ..< maxItems { + try db.insert(item: KissDB.Item(key: "hello\(i)", value: "world\(i)")) + } + + try db.commit() + let endTime = KissDB.appTime + print("DB count: \(db.count) insert elapsed: \(endTime - startTime)") + } + + + private func testInsertAll(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + for i in 0 ..< maxItems { + try db.insert(from: { item in + item.key = "hello\(i)" + item.value = "world\(i)" + return true + }) + } + + try db.commit() + let endTime = KissDB.appTime + print("DB count: \(db.count) insert elapsed: \(endTime - startTime)") + } + + + private func testSelectAll(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + + try db.select(into: { item in + print("\(item.value)") + return true + }) + + try db.rollback() + let endTime = KissDB.appTime + print("DB count: \(db.count) selectAll elapsed: \(endTime - startTime)") + } + + + private func testSelectEach(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + + for i in 0 ..< maxItems { + try db.select(key: "hello\(i)", into: { item in + print("\(item.value)") + return true + }) + } + + try db.rollback() + let endTime = KissDB.appTime + print("DB count: \(db.count) selectEach elapsed: \(endTime - startTime)") + } + + + private func testDeleteEach(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + + for i in 0 ..< maxItems { + try db.delete(key: "hello\(i)", into: { item in + print("\(item.value)") + return true + }) + } + + try db.commit() + let endTime = KissDB.appTime + print("DB count: \(db.count) deleteEach elapsed: \(endTime - startTime)") + } + + private func testDeleteAll(db: KissDB, maxItems: Int) throws { + let startTime = KissDB.appTime + try db.begin() + print("DB count: \(db.count)") + + for i in 0 ..< maxItems { + try db.delete(key: "hello\(i)") + } + + try db.commit() + let endTime = KissDB.appTime + print("DB count: \(db.count) deleteAll elapsed: \(endTime - startTime)") + } + + func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. @@ -25,36 +134,16 @@ final class KissMemeTests: XCTestCase { // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - let directory = URL.currentDirectory().appending(path: "testdb") - try? FileManager.default.removeItem(at: directory) - try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) - print(directory.path) + //let maxItems = 1_000_000 + let maxItems = 10 + let db = try KissDB(directory: testDBDirectory) - var startTime: TimeInterval, endTime: TimeInterval - - let db = try KissDB(directory: directory) - - startTime = KissDB.appTime - try db.begin() - print("DB count: \(db.count)") - for i in 0 ..< 1_000_000 { - try db.insert(item: KissDB.Item(key: "hello\(i)", value: "world\(i)")) - } - try db.commit() - endTime = KissDB.appTime - print("DB count: \(db.count) insert elapsed: \(endTime - startTime)") - - startTime = KissDB.appTime - try db.begin() - for i in 0 ..< 1_000_000 { - try db.delete(key: "hello\(i)", output: { item in - print("\(item.value)") - return true - }) - } - try db.commit() - endTime = KissDB.appTime - print("DB count: \(db.count) delete elapsed: \(endTime - startTime)") + try testInsert(db: db, maxItems: maxItems) + try testSelectAll(db: db, maxItems: maxItems) + try testSelectEach(db: db, maxItems: maxItems) + + try testInsertAll(db: db, maxItems: maxItems) + try testDeleteEach(db: db, maxItems: maxItems) } func testPerformanceExample() throws { diff --git a/kiss-db/kiss-db/kiss-db.c b/kiss-db/kiss-db/kiss-db.c index f588c73..717be0c 100644 --- a/kiss-db/kiss-db/kiss-db.c +++ b/kiss-db/kiss-db/kiss-db.c @@ -65,7 +65,6 @@ void kiss_db_destroy(kiss_db_ptr ptr) if (ptr == NULL) { return; } - mdb_cursor_close(ptr->cursor); mdb_dbi_close(ptr->env, ptr->dbi); mdb_env_close(ptr->env); free(ptr); @@ -123,7 +122,7 @@ kiss_bool kiss_db_insert(kiss_db_ptr ptr, kiss_db_item_t* item, kiss_bool update } -kiss_bool kiss_db_insert_bulk(kiss_db_ptr ptr, kiss_bool update, kiss_insert_callback callback, void* callback_user_ptr, kiss_db_error_t* error) +kiss_bool kiss_db_insert_from(kiss_db_ptr ptr, kiss_bool update, kiss_insert_callback callback, void* callback_user_ptr, kiss_db_error_t* error) { int rc = 0; unsigned int flags = 0; @@ -152,7 +151,7 @@ kiss_bool kiss_db_insert_bulk(kiss_db_ptr ptr, kiss_bool update, kiss_insert_cal } -kiss_bool kiss_db_delete(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_delete_callback callback, void* callback_user_ptr, kiss_db_error_t* error) +kiss_bool kiss_db_delete(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_db_error_t* error) { int rc = 0; MDB_val key, data; @@ -162,20 +161,45 @@ kiss_bool kiss_db_delete(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_s kiss_db_item_t item; - while (true) { - rc = mdb_del(ptr->txn, ptr->dbi, &key, &data); - if (rc == MDB_NOTFOUND) { - break; - } - CHECK_RET_ERROR(rc, false); - - item.data = data.mv_data; - item.data_size = data.mv_size; - - if (false == callback(&item, callback_user_ptr)) { - break; - } + rc = mdb_del(ptr->txn, ptr->dbi, &key, NULL); + if (rc == MDB_NOTFOUND) { + return true; } + CHECK_RET_ERROR(rc, false); + + item.data = data.mv_data; + item.data_size = data.mv_size; + + return true; +} + + +kiss_bool kiss_db_delete_into(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_delete_callback callback, void* callback_user_ptr, kiss_db_error_t* error) { + int rc = 0; + MDB_val key, data; + + CHECK_RET_ERROR(mdb_cursor_open(ptr->txn, ptr->dbi, &ptr->cursor), false); + + key.mv_data = (void*)in_key; + key.mv_size = in_key_size; + + kiss_db_item_t item; + + if ((rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT_DUP)) == 0) { + do { + item.key = key.mv_data; + item.key_size = key.mv_size; + item.data = data.mv_data; + item.data_size = data.mv_size; + + if (false == callback(&item, callback_user_ptr)) { + break; + } + CHECK_RET_ERROR(mdb_cursor_del(ptr->cursor, 0), false); + } while ((rc = mdb_cursor_get(ptr->cursor, &key, NULL, MDB_NEXT_DUP)) == 0); + } + + mdb_cursor_close(ptr->cursor); return true; } @@ -194,11 +218,13 @@ kiss_bool kiss_db_select(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_s while ((rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT_DUP)) == 0) { item.key = key.mv_data; - item.key_size = (kiss_uint)key.mv_size; + item.key_size = key.mv_size; item.data = data.mv_data; item.data_size = data.mv_size; - callback(&item, callback_user_ptr); + if (false == callback(&item, callback_user_ptr)) { + break; + } } mdb_cursor_close(ptr->cursor); @@ -206,7 +232,7 @@ kiss_bool kiss_db_select(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_s } -kiss_bool kiss_db_select_bulk(kiss_db_ptr ptr, kiss_select_callback callback, void* callback_user_ptr, kiss_db_error_t* error) +kiss_bool kiss_db_select_all(kiss_db_ptr ptr, kiss_select_callback callback, void* callback_user_ptr, kiss_db_error_t* error) { int rc = 0; MDB_val key, data; @@ -217,7 +243,7 @@ kiss_bool kiss_db_select_bulk(kiss_db_ptr ptr, kiss_select_callback callback, vo while ((rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT)) == 0) { item.key = key.mv_data; - item.key_size = (kiss_uint)key.mv_size; + item.key_size = key.mv_size; item.data = data.mv_data; item.data_size = data.mv_size; diff --git a/kiss-db/kiss-db/kiss-db.h b/kiss-db/kiss-db/kiss-db.h index db70ebe..b660bc4 100644 --- a/kiss-db/kiss-db/kiss-db.h +++ b/kiss-db/kiss-db/kiss-db.h @@ -40,7 +40,7 @@ typedef struct { typedef struct { void* key; - kiss_uint key_size; + kiss_uint64 key_size; void* data; kiss_uint64 data_size; } kiss_db_item_t; @@ -65,12 +65,13 @@ kiss_bool kiss_db_commit(kiss_db_ptr ptr, kiss_db_error_t* error); kiss_bool kiss_db_rollback(kiss_db_ptr ptr, kiss_db_error_t* error); kiss_bool kiss_db_insert(kiss_db_ptr ptr, kiss_db_item_t* item, kiss_bool update, kiss_db_error_t* error); -kiss_bool kiss_db_insert_bulk(kiss_db_ptr ptr, kiss_bool update, kiss_insert_callback callback, void* callback_user_ptr, kiss_db_error_t* error); +kiss_bool kiss_db_insert_from(kiss_db_ptr ptr, kiss_bool update, kiss_insert_callback callback, void* callback_user_ptr, kiss_db_error_t* error); -kiss_bool kiss_db_delete(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_delete_callback callback, void* callback_user_ptr, kiss_db_error_t* error); +kiss_bool kiss_db_delete(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_db_error_t* error); +kiss_bool kiss_db_delete_into(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_delete_callback callback, void* callback_user_ptr, kiss_db_error_t* error); kiss_bool kiss_db_select(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_size, kiss_select_callback callback, void* callback_user_ptr, kiss_db_error_t* error); -kiss_bool kiss_db_select_bulk(kiss_db_ptr ptr, kiss_select_callback callback, void* callback_user_ptr, kiss_db_error_t* error); +kiss_bool kiss_db_select_all(kiss_db_ptr ptr, kiss_select_callback callback, void* callback_user_ptr, kiss_db_error_t* error); kiss_int64 kiss_db_count(kiss_db_ptr ptr);