The first version of KissDB done
This commit is contained in:
@@ -81,7 +81,7 @@ public class KissDB: NSObject {
|
||||
|
||||
cItem.pointee.key = UnsafeMutableRawPointer(key.mutableString)
|
||||
cItem.pointee.key_size = UInt64(key.size)
|
||||
cItem.pointee.data = UnsafeMutableRawPointer(key.mutableString)
|
||||
cItem.pointee.data = UnsafeMutableRawPointer(value.mutableString)
|
||||
cItem.pointee.data_size = UInt64(value.size)
|
||||
|
||||
guard kiss_db_insert(cPtr, cItem, true, cError) else {
|
||||
@@ -89,11 +89,11 @@ public class KissDB: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
public func insert(from: ((Item)->Bool)?) throws {
|
||||
let obj = CallbackObject(itemCallback: from)
|
||||
public func insert(from: @escaping ((Int)->Item?), count: Int) throws {
|
||||
let obj = InsertCallbackObject(insertCallback: from, maxCount: count)
|
||||
let userPtr = Unmanaged.passUnretained(obj).toOpaque()
|
||||
|
||||
guard kiss_db_insert_from(cPtr, true, CallbackObject.insertCallback, userPtr, cError) else {
|
||||
guard kiss_db_insert_from(cPtr, false, InsertCallbackObject.insertCallback, userPtr, cError) else {
|
||||
throw KissDBError.general(cError.code, cError.message)
|
||||
}
|
||||
}
|
||||
@@ -109,9 +109,9 @@ public class KissDB: NSObject {
|
||||
public func delete(key: String, into: ((Item)->Bool)?) throws {
|
||||
let key = CString(key)
|
||||
|
||||
let obj = CallbackObject(itemCallback: into)
|
||||
let obj = ItemCallbackObject(itemCallback: into)
|
||||
let userPtr = Unmanaged.passUnretained(obj).toOpaque()
|
||||
guard kiss_db_delete_into(cPtr, key.mutableString, UInt32(key.size), CallbackObject.deleteCallback, userPtr, cError) else {
|
||||
guard kiss_db_delete_into(cPtr, key.mutableString, UInt32(key.size), ItemCallbackObject.deleteCallback, userPtr, cError) else {
|
||||
throw KissDBError.general(cError.code, cError.message)
|
||||
}
|
||||
}
|
||||
@@ -119,24 +119,62 @@ public class KissDB: NSObject {
|
||||
public func select(key: String, into: ((Item)->Bool)?) throws {
|
||||
let key = CString(key)
|
||||
|
||||
let obj = CallbackObject(itemCallback: into)
|
||||
let obj = ItemCallbackObject(itemCallback: into)
|
||||
let userPtr = Unmanaged.passUnretained(obj).toOpaque()
|
||||
guard kiss_db_select(cPtr, key.mutableString, UInt32(key.size), CallbackObject.selectCallback, userPtr, cError) else {
|
||||
guard kiss_db_select(cPtr, key.mutableString, UInt32(key.size), ItemCallbackObject.selectCallback, userPtr, cError) else {
|
||||
throw KissDBError.general(cError.code, cError.message)
|
||||
}
|
||||
}
|
||||
|
||||
public func select(into: ((Item)->Bool)?) throws {
|
||||
let obj = CallbackObject(itemCallback: into)
|
||||
let obj = ItemCallbackObject(itemCallback: into)
|
||||
let userPtr = Unmanaged.passUnretained(obj).toOpaque()
|
||||
guard kiss_db_select_all(cPtr, CallbackObject.selectCallback, userPtr, cError) else {
|
||||
guard kiss_db_select_all(cPtr, ItemCallbackObject.selectCallback, userPtr, cError) else {
|
||||
throw KissDBError.general(cError.code, cError.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CallbackObject: NSObject {
|
||||
class InsertCallbackObject: NSObject {
|
||||
|
||||
let insertCallback: ((Int)->KissDB.Item?)
|
||||
let maxCount: Int
|
||||
|
||||
private var index: Int = 0
|
||||
private var cKey: CString?
|
||||
private var cValue: CString?
|
||||
|
||||
init(insertCallback: @escaping ((Int)->KissDB.Item?), maxCount: Int) {
|
||||
self.insertCallback = insertCallback
|
||||
self.maxCount = maxCount
|
||||
}
|
||||
|
||||
static let insertCallback: kiss_insert_callback = { (item: UnsafeMutablePointer<kiss_db_item_t>?, userPtr: UnsafeMutableRawPointer?) -> kiss_bool in
|
||||
let obj = Unmanaged<InsertCallbackObject>.fromOpaque(userPtr!).takeUnretainedValue()
|
||||
guard let item = item else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard obj.index < obj.maxCount, let newItem = obj.insertCallback(obj.index) else {
|
||||
return false
|
||||
}
|
||||
obj.index += 1
|
||||
obj.cKey = CString(newItem.key)
|
||||
obj.cValue = CString(newItem.value)
|
||||
|
||||
item.pointee.key = UnsafeMutableRawPointer(obj.cKey!.mutableString)
|
||||
item.pointee.key_size = UInt64(obj.cKey!.size)
|
||||
item.pointee.data = UnsafeMutableRawPointer(obj.cValue!.mutableString)
|
||||
item.pointee.data_size = UInt64(obj.cValue!.size)
|
||||
|
||||
// Continue to insert remained items
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ItemCallbackObject: NSObject {
|
||||
|
||||
let itemCallback: ((KissDB.Item)->Bool)?
|
||||
|
||||
@@ -144,28 +182,8 @@ class CallbackObject: NSObject {
|
||||
self.itemCallback = itemCallback
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// Continue to insert remained items
|
||||
return true
|
||||
}
|
||||
|
||||
static let deleteCallback: kiss_delete_callback = { (item: UnsafeMutablePointer<kiss_db_item_t>!, userPtr: UnsafeMutableRawPointer?) -> kiss_bool in
|
||||
let obj = Unmanaged<CallbackObject>.fromOpaque(userPtr!).takeUnretainedValue()
|
||||
let obj = Unmanaged<ItemCallbackObject>.fromOpaque(userPtr!).takeUnretainedValue()
|
||||
if let itemCallback = obj.itemCallback, let item = item {
|
||||
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))
|
||||
@@ -179,7 +197,7 @@ class CallbackObject: NSObject {
|
||||
}
|
||||
|
||||
static let selectCallback: kiss_select_callback = { (item: UnsafeMutablePointer<kiss_db_item_t>!, userPtr: UnsafeMutableRawPointer?) -> kiss_bool in
|
||||
let obj = Unmanaged<CallbackObject>.fromOpaque(userPtr!).takeUnretainedValue()
|
||||
let obj = Unmanaged<ItemCallbackObject>.fromOpaque(userPtr!).takeUnretainedValue()
|
||||
if let itemCallback = obj.itemCallback, let item = item {
|
||||
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))
|
||||
|
||||
@@ -27,7 +27,7 @@ final class KissMemeTests: XCTestCase {
|
||||
}
|
||||
|
||||
|
||||
private func testInsert(db: KissDB, maxItems: Int) throws {
|
||||
private func testInsertEach(db: KissDB, maxItems: Int) throws {
|
||||
let startTime = KissDB.appTime
|
||||
try db.begin()
|
||||
print("DB count: \(db.count)")
|
||||
@@ -47,17 +47,13 @@ final class KissMemeTests: XCTestCase {
|
||||
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.insert(from: { (index) in
|
||||
KissDB.Item(key: "hello\(index)", value: "world\(index)")
|
||||
}, count: maxItems)
|
||||
|
||||
try db.commit()
|
||||
let endTime = KissDB.appTime
|
||||
print("DB count: \(db.count) insert elapsed: \(endTime - startTime)")
|
||||
print("DB count: \(db.count) insertAll elapsed: \(endTime - startTime)")
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +62,11 @@ final class KissMemeTests: XCTestCase {
|
||||
try db.begin()
|
||||
print("DB count: \(db.count)")
|
||||
|
||||
var index = 0
|
||||
try db.select(into: { item in
|
||||
print("\(item.value)")
|
||||
XCTAssertTrue(item.key == "hello\(index)")
|
||||
XCTAssertTrue(item.value == "world\(index)")
|
||||
index += 1
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -84,7 +83,9 @@ final class KissMemeTests: XCTestCase {
|
||||
|
||||
for i in 0 ..< maxItems {
|
||||
try db.select(key: "hello\(i)", into: { item in
|
||||
print("\(item.value)")
|
||||
//print("\(item.key) \(item.value)", "hello\(i) world\(i)")
|
||||
XCTAssertTrue(item.key == "hello\(i)")
|
||||
XCTAssertTrue(item.value == "world\(i)")
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -102,7 +103,9 @@ final class KissMemeTests: XCTestCase {
|
||||
|
||||
for i in 0 ..< maxItems {
|
||||
try db.delete(key: "hello\(i)", into: { item in
|
||||
print("\(item.value)")
|
||||
//print("\(item.key) \(item.value)", "hello\(i) world\(i)")
|
||||
XCTAssertTrue(item.key == "hello\(i)")
|
||||
XCTAssertTrue(item.value == "world\(i)")
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -138,19 +141,27 @@ final class KissMemeTests: XCTestCase {
|
||||
let maxItems = 10
|
||||
let db = try KissDB(directory: testDBDirectory)
|
||||
|
||||
try testInsert(db: db, maxItems: maxItems)
|
||||
try testSelectAll(db: db, maxItems: maxItems)
|
||||
try testInsertEach(db: db, maxItems: maxItems)
|
||||
try testSelectEach(db: db, maxItems: maxItems)
|
||||
try testDeleteEach(db: db, maxItems: maxItems)
|
||||
|
||||
try testInsertAll(db: db, maxItems: maxItems)
|
||||
try testDeleteEach(db: db, maxItems: maxItems)
|
||||
try testSelectAll(db: db, maxItems: maxItems)
|
||||
try testDeleteAll(db: db, maxItems: maxItems)
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
let maxItems = 1_000_000
|
||||
let db = try KissDB(directory: testDBDirectory)
|
||||
|
||||
// This is an example of a performance test case.
|
||||
measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
do {
|
||||
try testInsertEach(db: db, maxItems: maxItems)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -196,7 +196,8 @@ kiss_bool kiss_db_delete_into(kiss_db_ptr ptr, const void* in_key, kiss_uint in_
|
||||
break;
|
||||
}
|
||||
CHECK_RET_ERROR(mdb_cursor_del(ptr->cursor, 0), false);
|
||||
} while ((rc = mdb_cursor_get(ptr->cursor, &key, NULL, MDB_NEXT_DUP)) == 0);
|
||||
|
||||
} while ((rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT_DUP)) == 0);
|
||||
}
|
||||
|
||||
mdb_cursor_close(ptr->cursor);
|
||||
@@ -213,19 +214,34 @@ kiss_bool kiss_db_select(kiss_db_ptr ptr, const void* in_key, kiss_uint in_key_s
|
||||
|
||||
key.mv_data = (void*)in_key;
|
||||
key.mv_size = in_key_size;
|
||||
|
||||
data.mv_data = NULL;
|
||||
data.mv_size = 0;
|
||||
|
||||
kiss_db_item_t item;
|
||||
|
||||
while ((rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT_DUP)) == 0) {
|
||||
rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_SET);
|
||||
if (rc == MDB_NOTFOUND) {
|
||||
return true;
|
||||
}
|
||||
CHECK_RET_ERROR(rc, false);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mdb_cursor_get(ptr->cursor, &key, &data, MDB_NEXT_DUP);
|
||||
if (rc == MDB_NOTFOUND) {
|
||||
return true;
|
||||
}
|
||||
CHECK_RET_ERROR(rc, false);
|
||||
|
||||
} while (true);
|
||||
|
||||
mdb_cursor_close(ptr->cursor);
|
||||
return true;
|
||||
@@ -247,7 +263,9 @@ kiss_bool kiss_db_select_all(kiss_db_ptr ptr, kiss_select_callback callback, voi
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user