Working query functions
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user