Working query functions

This commit is contained in:
2023-06-08 08:54:54 +09:00
parent 4e11bf7d47
commit 4debf62971
4 changed files with 195 additions and 65 deletions

View File

@@ -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<kiss_db_item_t>?, userPtr: UnsafeMutableRawPointer?) -> kiss_bool in
let obj = Unmanaged<CallbackObject>.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

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);