1
0
mirror of https://github.com/danog/Telegram.git synced 2024-11-30 04:29:15 +01:00
Telegram/Share/PSLMDBKeyValueReaderWriter.m
2015-10-01 19:19:52 +03:00

269 lines
10 KiB
Objective-C

#import "PSLMDBKeyValueReaderWriter.h"
#import "PSLMDBTable.h"
#import "PSLMDBKeyValueCursor.h"
@interface PSLMDBKeyValueReaderWriter ()
{
PSLMDBTable *_table;
MDB_dbi _dbi;
MDB_txn *_txn;
}
@end
@implementation PSLMDBKeyValueReaderWriter
- (instancetype)initWithTable:(PSLMDBTable *)table transaction:(MDB_txn *)transaction
{
self = [super init];
if (self != nil)
{
_table = table;
_dbi = table.dbi;
_txn = transaction;
}
return self;
}
- (bool)readValueForRawKey:(PSConstData *)key value:(PSConstData *)value
{
if (key == NULL)
return false;
MDB_val mdbKey;
MDB_val mdbData;
mdbKey.mv_data = (uint8_t *)key->data;
mdbKey.mv_size = (size_t)key->length;
int rc = 0;
rc = mdb_get(_txn, _dbi, &mdbKey, &mdbData);
if (rc == MDB_SUCCESS)
{
if (value != NULL)
{
value->data = mdbData.mv_data;
value->length = (NSUInteger)mdbData.mv_size;
}
return true;
}
else
{
if (rc != MDB_NOTFOUND)
NSLog(@"[PSLMDBKeyValueReader mdb_get error %d]", rc);
return false;
}
}
- (void)writeValueForRawKey:(const uint8_t *)key keyLength:(NSUInteger)keyLength value:(const uint8_t *)value valueLength:(NSUInteger)valueLength
{
if (key == NULL || keyLength == 0)
return;
MDB_val mdbKey;
MDB_val mdbData;
mdbKey.mv_data = (uint8_t *)key;
mdbKey.mv_size = keyLength;
mdbData.mv_data = (uint8_t *)value;
mdbData.mv_size = valueLength;
int rc = 0;
rc = mdb_put(_txn, _dbi, &mdbKey, &mdbData, 0);
if (rc != MDB_SUCCESS)
NSLog(@"[PSLMDBKeyValueWriter mdb_put error %d]", rc);
}
- (void)readWithCursor:(void (^)(PSLMDBKeyValueCursor *))readWithCursorBlock
{
if (!readWithCursorBlock)
return;
MDB_cursor *cursor = NULL;
int rc = 0;
rc = mdb_cursor_open(_txn, _dbi, &cursor);
if (rc == MDB_SUCCESS)
{
readWithCursorBlock([[PSLMDBKeyValueCursor alloc] initWithTable:_table transaction:_txn cursor:cursor]);
mdb_cursor_close(cursor);
}
else
NSLog(@"[PSLMDBKeyValueWriter mdb_cursor_open error %d]", rc);
}
- (bool)readValueBetweenLowerBoundKey:(PSConstData *)lowerBoundKey upperBoundKey:(PSConstData *)upperBoundKey selectKey:(PSKeyValueReaderSelectKey)selectKey selectedKey:(PSConstData *)selectedKey selectedValue:(PSConstData *)selectedValue
{
__block bool result = false;
[self enumerateKeysAndValuesBetweenLowerBoundKey:lowerBoundKey upperBoundKey:upperBoundKey options:selectKey == PSKeyValueReaderSelectHigherKey ? PSKeyValueReaderEnumerationReverse : 0 withBlock:^(PSData *key, PSData *value, bool *stop)
{
if (selectedKey)
*selectedKey = *key;
if (selectedValue)
*selectedValue = *value;
if (stop)
*stop = true;
result = true;
}];
return result;
}
- (void)enumerateKeysAndValuesBetweenLowerBoundKey:(PSConstData *)lowerBoundKey upperBoundKey:(PSConstData *)upperBoundKey options:(NSInteger)options withBlock:(void (^)(PSConstData *key, PSConstData *value, bool *stop))block
{
if (!block || upperBoundKey == NULL || lowerBoundKey == NULL)
return;
[self readWithCursor:^(PSLMDBKeyValueCursor *cursor)
{
MDB_val upperBoundKeyVal = {.mv_data = (uint8_t *)upperBoundKey->data, .mv_size = upperBoundKey->length};
MDB_val lowerBoundKeyVal = {.mv_data = (uint8_t *)lowerBoundKey->data, .mv_size = lowerBoundKey->length};
if (options & PSKeyValueReaderEnumerationReverse)
{
uint8_t const *positionedKey = upperBoundKey->data;
NSUInteger positionedKeyLength = upperBoundKey->length;
uint8_t const *positionedValue = NULL;
NSUInteger positionedValueLength = 0;
if ([cursor positionAt:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength directionIfNotFound:PSKeyValueCursorDirectionBack])
{
MDB_val positionedKeyVal = {.mv_data = (uint8_t *)positionedKey, .mv_size = positionedKeyLength};
bool continueSearch = true;
if ((options & PSKeyValueReaderEnumerationUpperBoundExclusive) && mdb_cmp(_txn, _dbi, &upperBoundKeyVal, &positionedKeyVal) == 0)
{
continueSearch = [cursor previous:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength];
}
if (continueSearch)
{
int cmpResult = mdb_cmp(_txn, _dbi, &positionedKeyVal, &lowerBoundKeyVal);
if ((options & PSKeyValueReaderEnumerationLowerBoundExclusive) ? (cmpResult > 0) : (cmpResult >= 0))
{
bool stop = false;
PSData positionedKeyData = {.data = (uint8_t *)positionedKey, .length = positionedKeyLength};
PSData positionedValueData = {.data = (uint8_t *)positionedValue, .length = positionedValueLength};
block(&positionedKeyData, &positionedValueData, &stop);
while (!stop)
{
if (![cursor previous:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength])
break;
MDB_val positionedKeyVal = {.mv_data = (uint8_t *)positionedKey, .mv_size = positionedKeyLength};
int cmpResult = mdb_cmp(_txn, _dbi, &positionedKeyVal, &lowerBoundKeyVal);
if ((options & PSKeyValueReaderEnumerationLowerBoundExclusive) ? (cmpResult > 0) : (cmpResult >= 0))
{
PSData positionedKeyData = {.data = (uint8_t *)positionedKey, .length = positionedKeyLength};
PSData positionedValueData = {.data = (uint8_t *)positionedValue, .length = positionedValueLength};
block(&positionedKeyData, &positionedValueData, &stop);
}
else
break;
}
}
}
}
}
else
{
uint8_t const *positionedKey = lowerBoundKey->data;
NSUInteger positionedKeyLength = lowerBoundKey->length;
uint8_t const *positionedValue = NULL;
NSUInteger positionedValueLength = 0;
if ([cursor positionAt:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength directionIfNotFound:PSKeyValueCursorDirectionForward])
{
MDB_val positionedKeyVal = {.mv_data = (uint8_t *)positionedKey, .mv_size = positionedKeyLength};
bool continueSearch = true;
if ((options & PSKeyValueReaderEnumerationLowerBoundExclusive) && mdb_cmp(_txn, _dbi, &lowerBoundKeyVal, &positionedKeyVal) == 0)
{
continueSearch = [cursor next:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength];
}
if (continueSearch)
{
int cmpResult = mdb_cmp(_txn, _dbi, &positionedKeyVal, &upperBoundKeyVal);
if ((options & PSKeyValueReaderEnumerationUpperBoundExclusive) ? (cmpResult < 0) : (cmpResult <= 0))
{
bool stop = false;
PSData positionedKeyData = {.data = (uint8_t *)positionedKey, .length = positionedKeyLength};
PSData positionedValueData = {.data = (uint8_t *)positionedValue, .length = positionedValueLength};
block(&positionedKeyData, &positionedValueData, &stop);
while (!stop)
{
if (![cursor next:&positionedKey keyLength:&positionedKeyLength value:&positionedValue valueLength:&positionedValueLength])
break;
MDB_val positionedKeyVal = {.mv_data = (uint8_t *)positionedKey, .mv_size = positionedKeyLength};
int cmpResult = mdb_cmp(_txn, _dbi, &positionedKeyVal, &upperBoundKeyVal);
if ((options & PSKeyValueReaderEnumerationUpperBoundExclusive) ? (cmpResult < 0) : (cmpResult <= 0))
{
PSData positionedKeyData = {.data = (uint8_t *)positionedKey, .length = positionedKeyLength};
PSData positionedValueData = {.data = (uint8_t *)positionedValue, .length = positionedValueLength};
block(&positionedKeyData, &positionedValueData, &stop);
}
else
break;
}
}
}
}
}
}];
}
- (bool)deleteValueForRawKey:(PSData *)key
{
if (key == NULL || key->data == NULL || key->length == 0)
return false;
MDB_val mdbKey;
mdbKey.mv_data = (uint8_t *)key->data;
mdbKey.mv_size = (size_t)key->length;
int rc = 0;
rc = mdb_del(_txn, _dbi, &mdbKey, NULL);
if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND)
NSLog(@"[PSLMDBKeyValueWriter mdb_del error %d]", rc);
return rc == MDB_SUCCESS;
}
- (void)deleteAllValues
{
MDB_cursor *cursor = NULL;
int rc = 0;
rc = mdb_cursor_open(_txn, _dbi, &cursor);
if (rc == MDB_SUCCESS)
{
rc = mdb_cursor_get(cursor, NULL, NULL, MDB_FIRST);
while (rc == MDB_SUCCESS)
{
rc = mdb_cursor_del(cursor, 0);
rc = mdb_cursor_get(cursor, NULL, NULL, MDB_NEXT);
}
mdb_cursor_close(cursor);
}
}
@end