ObjectiveRocks
ObjectiveRocks 是 Facebook 的 RocksDB 的 Objective-C 封装 - 一种用于闪存和 RAM 存储的持久性键值存储。
当前 RocksDB 版本:v6.2.4
快速概览
RocksDB 是一个键值存储,其中的键和值是任意大小的字节流。键根据指定的比较函数在键值存储中进行排序。RocksDB 支持原子读写、快照、迭代和许多配置选项。
ObjectiveRocks 提供了一个容易的接口到 RocksDB,以及一个面向 Objective-C 的 API,它抽象了底层的 C++ 实现,所以您不必处理它。虽然不需要了解 RocksDB 的细节来使用这个包装器,但建议您对内部结构有基本的了解,这可以解释背后的 API 设计决策。
如果您对 RocksDB 的内部结构感兴趣,请参阅 RocksDB Wiki。
Swift
ObjectiveRocks提供了一个纯正的Objective-C接口,并且可以被用在Swift项目中。此外,ObjectRocks的所有测试也都转移到了Swift中。您可以查看包含OSX和iOS ObjectiveRocks实现的桥接头代码及其源代码的Tests
目标。
您需要了解的最低限度的知识
- 键和值是字节数组
- 数据库中的所有数据都通过给定的
Comparator
逻辑上按顺序排列 - RocksDB支持
列族
- 列族提供了一种逻辑分区数据库的方法,类似于MongoDB中的集合
- 可以独立配置
- 可以动态添加或删除
- 键值对与数据库中确切的一个
列族
相关联。 - 如果没有指定列族,则使用
默认
列族
- RocksDB提供了三个基本操作
- Get(key)
- Put(key, value)
- Delete(key)
- 应用程序可以通过
Merge Operator
定义一个合并操作- 合并是一个原子性的读-修改-写操作
- RocksDB提供了一个
Iterator
API来执行数据库上的RangeScan
- RocksDB提供了一个
Snapshot
API,允许应用程序创建数据库的即时点视图 - 有许多配置选项
- DBOptions: 控制数据库的行为
- ColumnFamilyOptions: 控制列族的行为
- ReadOptions: 应用到单个读取操作
- WriteOptions: 应用到单个写入操作
RocksDB Lite
ObjectiveRocks包含了两个目标,用于iOS和macOS。iOS目标构建了RocksDB Lite版本,该版本不包括完整的功能集。
这些功能仅适用于macOS
- 列族元数据
- 带有索引的写批处理
- 普通和Cuckoo表工厂
- 向量、哈希SkipList、哈希LinkList和哈希Cuckoo Memtable Rep工厂
- 数据库备份
- 数据库统计信息
- 数据库属性
- 线程状态
安装
Carthage
Carthage 是一种去中心化的依赖管理工具,它构建您的依赖并提供二进制框架。
如果您还没有安装 Carthage,可以使用以下命令通过 Homebrew 安装:
$ brew update
$ brew install carthage
要使用 Carthage 将 ObjectiveRocks
添加到您的项目中作为依赖,只需在您的 Cartfile
中添加以下行:
github "iabudiab/ObjectiveRocks"
然后运行以下命令以构建框架,并将构建的 ObjectiveRocks.framework
拖动到您的 Xcode 项目中。
$ carthage update
手动操作
1. 将 ObjectiveRocks
添加为 git 子模块
$ git submodule add https://github.com/iabudiab/ObjectiveRocks.git
2. 打开 ObjectiveRocks
文件夹,并将 ObjectiveRocks.xcodeproj
拖放到 Xcode 的 Project Navigator 中,将其添加为子项目。
3. 在您的目标 General 面板下,在 Embedded Binaries
下添加 ObjectiveRocks.framework
注意,ObjectiveRocks 依赖于 RocksDB 并将其作为 Git 子模块包含在内。
使用说明
为了简洁起见,README 将使用
NSString
表示法代替NSData
中的密钥和值!
打开和关闭数据库实例
要打开数据库,您必须指定其位置
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db"];
...
[db close];
RocksDB
提供许多配置设置,可以在打开数据库时指定。为此 ObjectiveRocks
提供了一个基于 blocks 的初始化器。您需要的最低配置是 createIfMissing
,以便在数据库不存在的情况下创建一个新的数据库
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.createIfMissing = YES;
}];
列出了所有当前可用的选项及其说明。
更健壮的设置可能看起来像这样
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.createIfMissing = YES;
options.maxOpenFiles = 50000;
options.tableFacotry = [RocksDBTableFactory blockBasedTableFactoryWithOptions:^(RocksDBBlockBasedTableOptions *options) {
options.filterPolicy = [RocksDBFilterPolicy bloomFilterPolicyWithBitsPerKey:10];
options.blockCache = [RocksDBCache LRUCacheWithCapacity:1024 * 1024 * 1024];
options.blockSize = 64 * 1024;
}];
options.writeBufferSize = 64 * 1024 * 1024;
options.maxWriteBufferNumber = 7;
options.targetFileSizeBase = 64 * 1024 * 1024;
options.numLevels = 7;
options.maxLogFileSize = 50 * 1024 * 1024;
options.keepLogFileNum = 30;
}];
基本操作
数据库提供三项基本操作,即Put
(存储)、Get
(查询)和Delete
(删除)以存储/查询数据。RocksDB中的键和值是任意字节数组
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.createIfMissing = YES;
}];
NSData *data = [@"World" dataUsingEncoding:NSUTF8StringEncoding]
NSData *key = [@"Hello" dataUsingEncoding:NSUTF8StringEncoding]
[db storeData:data forKey:key];
NSData *get = [db getDataForKey:key];
[db deleteDataForKey:key];
读写错误
数据库操作可以通过传递一个NSError
引用来检查是否发生了任何错误
NSError *error = nil;
[db setObject:object forKey:key error:&error];
NSMutableDictionary *dictionary = [db dataForKey:@"Hello" error:&error];
[db deleteDataForKey:@"Hello" error:&error];
读写选项
可以通过特定的选项来调整每个单个的读写操作
[db setObject:anObject forKey:aKey writeOptions:^(RocksDBWriteOptions *writeOptions) {
writeOptions.syncWrites = YES;
writeOptions.disableWriteAheadLog = YES;
writeOptions.timeoutHint = 5;
writeOptions.ignoreMissingColumnFamilies = NO;
}];
[db dataForKey:aKey readOptions:^(RocksDBReadOptions *readOptions) {
readOptions.verifyChecksums = YES;
readOptions.fillCache = NO;
}];
在RocksDB
或RocksDBColumnFamily
实例上也可以设置默认选项
[db setDefaultReadOptions:^(RocksDBReadOptions *readOptions) {
readOptions.fillCache = YES;
readOptions.verifyChecksums = YES;
} andWriteOptions:^(RocksDBWriteOptions *writeOptions) {
writeOptions.syncWrites = YES;
writeOptions.timeoutHint = 5;
}];
您可以在配置指南中了解更多关于读写选项的信息
迭代
迭代是通过RocksDBIterator
类提供的。
您可以手动迭代
RocksDB *db = ...;
RocksDBColumnFamily *stuffColumnFamily = .../
RocksDBIterator *iterator = [db iterator];
RocksDBIterator *cfIterator = [stuffColumnFamily iterator];
// Alternatively, you can get an iterator with specific read options
iterator = [db iteratorWithReadOptions:^(RocksDBReadOptions *readOptions) {
// Read options here
}];
for ([iterator seekToKey:@"start"]; [iterator isValid]; [iterator next]) {
NSLog(@"%@: %@", [iterator key], [iterator value]);
// Iterates all keys starting from key "start"
}
或者使用提供的一个枚举块
[db setData:@"Value 1" forKey:@"A"];
[db setData:@"Value 2" forKey:@"B"];
[db setData:@"Value 3" forKey:@"C"];
[db setData:@"Value 3" forKey:@"D"];
RocksDBIterator *iterator = [db iterator];
/* Keys Enumeration */
[db enumerateKeysUsingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@", key);
// A, B, C, D
}];
// reverse enumeration
[db enumerateKeysInReverse:YES usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@", key);
// D, C, B, A
}];
// Enumeration in a given key-range [start, end)
RocksDBIteratorKeyRange range = RocksDBMakeKeyRange(@"A", @"C");
[db enumerateKeysInRange:range reverse:NO usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@", key, [db dataForKey:key]);
// B, C
}];
/* Key-Value Enumeration */
[db enumerateKeysAndValuesUsingBlock:^(NSData *key, NSData *value BOOL *stop) {
NSLog(@"%@:%@", key, value);
// A:1, B:2, C:3, D:4
}];
[db enumerateKeysAndValuesInReverse:YES usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@: %@", key, [db dataForKey:key]);
// D:4, C:3, B:2, A:1
}];
// Enumeration in a given key-range [start, end)
RocksDBIteratorKeyRange range = RocksDBMakeKeyRange(@"A", @"C");
[db enumerateKeysAndValuesInRange:range reverse:YES usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@:%@", key, [db dataForKey:key]);
// B:2, C:3
}];
前缀遍历迭代
RocksDBIterator
可以通过提供RocksDBPrefixExtractor
来支持在键前缀内进行迭代。这样一个提取器是内置的,并且为每个键提取固定长度的前缀
RocksDB *db = [RocksDB databaseAtPath:_path andDBOptions:^(RocksDBOptions *options) {
options.createIfMissing = YES;
options.prefixExtractor = [RocksDBPrefixExtractor prefixExtractorWithType:RocksDBPrefixFixedLength length:2];
}];
[db setData:@"a" forKey:@"10.1"];
[db setData:@"b" forKey:@"10.2"];
[db setData:@"b" forKey:@"10.3"];
[db setData:@"c" forKey:@"11.1"];
[db setData:@"d" forKey:@"11.2"];
[db setData:@"d" forKey:@"11.3"];
RocksDBIterator *iterator = [db iterator];
// Enumeration starts with the key that is Greater-Than-Or-Equal to a key
// with the given "prefix" parameter
[iterator enumerateKeysWithPrefix:@"10" usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@", key);
// 10.1, 10.2, 10.3
}];
// .. so in this case the enumeration starts at key "10.2", even if "10.1"
// has the same prefix
[iterator enumerateKeysWithPrefix:@"10.2" usingBlock:^(NSData *key, BOOL *stop) {
NSLog(@"%@", key);
// 10.2, 10.3
}];
您还可以定义自己的前缀提取器
RocksDBPrefixExtractor *extractor = [[RocksDBPrefixExtractor alloc] initWithName:@"custom_prefix"
transformBlock:^id (NSData *key) {
// Apply your key transformation to extract the prefix part
id prefix = extractPrefixFromKey(key);
return prefix;
}
prefixCandidateBlock:^BOOL (NSData *key) {
// You can filter out keys that are not viable candidates for
// your custom prefix format, e.g. key length is smaller than
// the target prefix length
BOOL isCandidate = canExtractPrefixFromKey(key);
return isCandidate;
}
validPrefixBlock:^BOOL (NSData *prefix) {
// After a prefix is extracted you can perform extra
// checks here to verify that the prefix is valid
BOOL isValid = isExtractedPrefixValid(prefix);
return isValid;
}
];
列族
一旦您有了RocksDB
实例,您可以动态地创建和删除列族
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:...];
RocksDBColumnFamily *columnFamily = [db createColumnFamilyWithName:@"new_column_family" andOptions:^(RocksDBColumnFamilyOptions *options) {
// Options for the new column family
};
// Do stuff with columnFamily and close it when you're done
[columnFamily close];
// To drop it
[columnFamily drop];
注意,
RocksDBColumnFamily
是RocksDB
的一个子类。
如果数据库已存在除默认以外的列族,则在打开它时需要指定数据库中目前存在的所有列族,包括默认列族。您使用 RocksDBColumnFamiliesDescriptor
对象来指定列族。
RocksDBColumnFamilyDescriptor *descriptor = [RocksDBColumnFamilyDescriptor new];
[descriptor addColumnFamilyWithName:@"default" andOptions:^(RocksDBColumnFamilyOptions *options) {
// Options for the default column family
}];
[descriptor addColumnFamilyWithName:@"stuff_column_family" andOptions:^(RocksDBColumnFamilyOptions *options) {
// Options for the stuff_column_family
}];
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" columnFamilies:descriptor andDatabaseOptions:^(RocksDBDatabaseOptions *options) {
// Database options here
}];
NSArray *columnFamilies = db.columnFamilies;
RocksDBColumnFamily *defaultColumnFamily = columnFamilies[0];
RocksDBColumnFamily *stuffColumnFamily = columnFamilies[1];
// At this point you can either use the db instance or
// the defaultColumnFamily instance to access the default column family
原子更新
可以使用 WriteBatch
在数据库上原子地应用一组更新。使用 WriteBatch
有两种方式:
- 一个基于内部块的方法
[db setData:@"Value 1" forKey:@"Key 1"];
[db performWriteBatch:^(RocksDBWriteBatch *batch, RocksDBWriteOptions *writeOptions) {
[batch setData:@"Value 2" forKey:@"Key 2"];
[batch setData:@"Value 3" forKey:@"Key 3"];
[batch deleteDataForKey:@"Key 1"];
}];
- 通过
WriteBatch
实例,这可能在“零散”逻辑中更灵活
[db setData:@"Value 1" forKey:@"Key 1"];
RocksDBWriteBatch *batch = [db writeBatch];
[batch setData:@"Value 2" forKey:@"Key 2"];
[batch setData:@"Value 3" forKey:@"Key 3"];
[batch deleteDataForKey:@"Key 1"];
...
[db applyWriteBatch:batch withWriteOptions:^(RocksDBWriteOptions *writeOptions) {
// Write options here
}];
默认情况下,Write Batch 对象会在与 DB 实例关联的列族上操作,该实例用于创建它。但是,您也可以指定列族,以实现跨多个列族的原子写入。在这种情况下,应用批处理的具体实例无关紧要
RocksDB *db = ...;
RocksDBColumnFamily *stuffColumnFamily = .../
// Write Batch for default column family
RocksDBWriteBatch *batch = [db writeBatch];
// Write Batch for stuffColumnFamily
RocksDBWriteBatch *cfBatch = [stuffColumnFamily writeBatch];
[batch setData:@"Value 1" forKey:@"Key 1"];
[batch setData:@"Value 2" forKey:@"Key 2" inColumnFamily:stuffColumnFamily];
// You can apply the Write Batch object either on the DB instance
// or the stuffColumnFamily instance.
// The following two calls have the same effect:
/**
[db applyWriteBatch:batch withWriteOptions:^(RocksDBWriteOptions *writeOptions) {
// Write options here
}];
[stuffColumnFamily applyWriteBatch:batch withWriteOptions:^(RocksDBWriteOptions *writeOptions) {
// Write options here
}];
*/
快照
快照提供了一个关于键值存储状态的只读一致视图。当不再需要时,别忘了关闭快照。
[db setData:@"Value 1" forKey:@"A"];
RocksDBSnapshot *snapshot = [db snapshot];
// Alternatively, you can get a snapshot with specific read options
snapshot = [db snapshotWithReadOptions:^(RocksDBReadOptions *readOptions) {
// Read options here
}];
[db deleteDataForKey:@"A"];
[db setData:@"Value 2" forKey:@"B"];
NSString *value1 = [snapshot dataForKey:@"A"];
// value1 == @"Value 1"
NSString *value2 = [snapshot dataForKey:@"B"];
// value2 == nil
...
[snapshot close];
检查点
检查点是在时间点上的一个可打开的数据库快照。
[db setData:@"Value 1" forKey:@"A"];
[db setData:@"Value 2" forKey:@"B"];
RocksDBCheckpoint *checkpoint = [[RocksDBCheckpoint alloc] initWithDatabase:db];
NSError *error = nil;
[checkpoint createCheckpointAtPath:@"path/to/checkpoint" error:&error];
RocksDB *db2 = [RocksDB databaseAtPath:@"path/to/checkpoint"];
...
[db close];
[db2 close];
键比较器
键值存储中的键是按照指定的比较函数顺序排列的。默认的键排序函数按字典顺序排序字节。
通过在打开数据库时提供自定义比较器,可以更改此行为,使用 RocksDBComparator
。
假设你有 NSString
键,并且想要它们使用不区分大小写的、基于区域的比较来排序
RocksDBComparator *localizedKeys = [[RocksDBComparator alloc] initWithName:@"LocalizedKeys" andBlock:^int (NSData *key1, NSData *key2) {
return [key1 localizedCaseInsensitiveCompare:key2];
];
RocksDB *db = [RocksDB databaseAtPath:_path andDBOptions:^(RocksDBOptions *options) {
options.comparator = localizedKeys;
}];
比较器的名称在创建数据库时附加到数据库上,并且在每次后续打开数据库时都会检查。如果名称更改,则打开调用将失败。因此,如果新的键格式和比较函数与现有数据库不兼容,则需要更改名称,并且可以安全地丢弃现有数据库的内容。
内置比较器
ObjectiveRocks具有一些内置比较器,可以使用如下方式
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.comparator = [RocksDBComparator comaparatorWithType:RocksDBComparatorNumberAscending];
}];
RocksDBComparatorBytewiseAscending:
以字典序升序对键进行排序。- 如果没有指定,这将是默认行为。
RocksDBComparatorBytewiseDescending
以字典序降序对键进行排序。RocksDBComparatorStringCompareAscending
通过compare
选择器以升序对NSString
键进行排序。- 该比较器假设
NSString
键,并通过initWithData:encoding:
使用UTF-8对关联的NSData
进行编码
- 该比较器假设
RocksDBComparatorStringCompareDescending
通过compare
选择器以降序对NSString
键进行排序。- 该比较器假设
NSString
键,并通过initWithData:encoding:
使用UTF-8对关联的NSData
进行编码
- 该比较器假设
合并操作符
合并操作符是RocksDB中的一种原子性读取-修改-写入操作。有关详细描述,请访问RocksDB项目的合并操作符维基页面。
与
comparator
类似,使用一个merge operator
创建的数据库无法用另一个打开。
关联合并操作符
当您有关联数据时可以使用此合并操作符
- 您的合并操作数格式与您的Put值相同,并且
- 可以将多个操作数合并为一个(只要它们是同一顺序的)
例如,我们可以使用合并操作符将条目追加到现有数组中,而不是完全读取它、更新它并写回
RocksDBMergeOperator *arrayAppend = [RocksDBMergeOperator operatorWithName:@"ArrayAppend" andBlock:^id (NSData *key, NSData *existingValue, NSData *mergeValue) {
if (existingValue == nil) {
return mergeValue;
} else {
[existingValue addObjectsFromArray:mergeValue];
return existingValue;
}
}];
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.mergeOperator = arrayAppend;
}];
NSMutableArray *letters = [NSMutableArray arrayWithObjects:@"A", @"B", nil];
[db setData:letters forKey:@"Key"];
[db mergeData:@[@"C", @"D"] forKey:@"Key"];
[db mergeData:@[@"E"] forKey:@"Key"];
NSMutableArray *merged = [db dataForKey:@"Key"];
// merged = @[@"A", @"B", @"C", @"D", @"E"];
通用合并操作符
如果两个关联约束中的任何一个都不成立,则使用通用合并操作符。
通用合并操作符有两个方法,PartialMerge,FullMerge
-
PartialMerge:用于组合两个合并操作数(如果可能)。如果客户端指定的操作符可以逻辑上处理将两个合并操作数组合成一个单一操作数,则应在此方法中提供执行的语义,然后它应返回一个非nil对象。如果返回
nil
,则表示两个合并操作数不能组合成一个。 -
FullMerge:此函数接收一个现有值和一个已入栈的操作数列表。客户端指定的合并操作符应逐个应用操作数,并返回结果对象。如果返回值为
nil
,则表示失败,即损坏的数据、错误等。
ObjectiveRocks引入了一个新的mergeOperation
方法,用于与通用合并操作符一起使用。这个假设的例子展示了如何使用客户端定义的合并操作与通用合并操作符一起使用。
RocksDBMergeOperator *mergeOp = [RocksDBMergeOperator operatorWithName:@"operator"
partialMergeBlock:^id(NSData *key, NSData *leftOperand, NSData *rightOperand) {
NSString *left = [leftOperand componentsSeparatedByString:@":"][0];
NSString *right = [rightOperand componentsSeparatedByString:@":"][0];
if ([left isEqualToString:right]) {
return rightOperand;
}
return nil;
} fullMergeBlock:^id(id key, id *existing, NSArray *operands) {
for (NSString *operand in operands) {
NSArray *components = [operand componentsSeparatedByString:@":"];
NSString *action = components[1];
if ([action isEqualToString:@"DELETE"]) {
[existing removeObjectForKey:components[0]];
} else {
existing[comp[0]] = components[2];
}
}
return existing;
}
];
RocksDB *db = [RocksDB databaseAtPath:_path andDBOptions:^(RocksDBOptions *options) {
options.createIfMissing = YES;
options.mergeOperator = mergeOp;
}];
NSDictionary *object = @{@"Key 1" : @"Value 1",
@"Key 2" : @"Value 2",
@"Key 3" : @"Value 3"};
[db setObject:object forKey:@"Dict Key"];
[db mergeData:@"Key 1:UPDATE:Value X" forKey:@"Dict Key"];
[db mergeData:@"Key 4:INSERT:Value 4" forKey:@"Dict Key"];
[db mergeData:@"Key 2:DELETE" forKey:@"Dict Key"];
[db mergeData:@"Key 1:UPDATE:Value 1 New" forKey:@"Dict Key"];
id result = [db dataForKey:@"Dict Key"];
/**
result = @{@"Key 1" : @"Value 1 New",
@"Key 3" : @"Value 3",
@"Key 4" : @"Value 4"};
*/
环境 & 线程状态
RocksDBEnv
允许修改后台作业的线程池。RocksDB使用此线程池进行压缩和内存表刷新。
RocksDBEnv *dbEnv = [RocksDBEnv envWithLowPriorityThreadCount:12 andHighPriorityThreadCount:4];
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.env = dbEnv;
}];
// To get a list of all threads
NSArray *threads = dbEnv.threadList;
// "threads" array contains objects of type RocksDBThreadStatus
RocksDBThreadStatus *status = threads[0];
备份 & 还原
使用RocksDBBackupEngine
备份数据库
RocksDB *db = ...
RocksDBBackupEngine *backupEngine = [[RocksDBBackupEngine alloc] initWithPath:@"path/to/backup"];
NSError *error = nil;
[backupEngine createBackupForDatabase:db error:&error];
...
[backupEngine close];
还原数据库备份
RocksDBBackupEngine *backupEngine = [[RocksDBBackupEngine alloc] initWithPath:@"path/to/backup"];
backupEngine restoreBackupToDestinationPath:@"path/to/db" error:nil];
backupEngine close];
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db"];
...
[db2 close];
备份是增量备份,只将新数据复制到备份目录,因此您可以
- 检索所有可用的备份信息
- 还原特定增量备份而不是最后一个备份
- 删除特定的备份
- 保留最后N个备份并清除所有其他备份
RocksDB *db = ...
RocksDBBackupEngine *backupEngine = [[RocksDBBackupEngine alloc] initWithPath:@"path/to/backup"];
[db setData:@"Value 1" forKey:@"A"];
[backupEngine createBackupForDatabase:db error:nil];
[db setData:@"Value 2" forKey:@"B"];
[backupEngine createBackupForDatabase:db error:nil];
[db setData:@"Value 3" forKey:@"C"];
[backupEngine createBackupForDatabase:db error:nil];
// An array containing RocksDBBackupInfo objects
NSArray *backupInfo = backupEngine.backupInfo;
// Restore second backup
[backupEngine restoreBackupWithId:2 toDestinationPath:@"path/to/db" error:nil];
// Delete first backup
[backupEngine deleteBackupWithId:1 error:nil];
// Purge all except the last two
[backupEngine purgeOldBackupsKeepingLast:2 error:nil];
统计信息
您可以通过在数据库选项中创建和设置RocksDBStatistics
对象来收集这些统计信息
RocksDBStatistics *dbStatistics = [RocksDBStatistics new];
RocksDB *db = [RocksDB databaseAtPath:@"path/to/db" andDBOptions:^(RocksDBOptions *options) {
options.statistics = dbStatistics;
}];
...
[dbStatistics countForTicker:RocksDBTickerBytesRead];
RocksDBStatisticsHistogram *dbGetHistogram = [dbStatistics histogramDataForType:RocksDBHistogramDBGet];
在RocksDBStatistics.h
中定义了可用的计时器和直方图
属性
数据库通过列族级别的属性导出有关其状态的一些信息。在RocksDBProperties.h
中定义了可用的属性
RocksDB *db = ...
NSString *dbStats = [db valueForProperty:RocksDBPropertyDBStats];
uint64_t sizeActiveMemTable = [db valueForIntProperty:RocksDBIntPropertyCurSizeActiveMemTable];
配置
目前只封装/提供RocksDB所有选项的一个子集。
稍后将添加其他选项(大多是在我有时间试验并且了解它们的功能时)。
ObjectiveRocks 数据库选项
选项 | 描述 | 默认值 |
---|---|---|
createIfMissing | 如果数据库缺失,将创建数据库 | false |
createMissingColumnFamilies | 自动创建缺失的列族 | false |
errorIfExists | 如果数据库已存在,则抛出错误 | false |
paranoidChecks | RocksDB 會積極檢查數據的一致性 | true |
infoLogLevel | 日志级别 | INFO |
maxOpenFiles | DB可以使用的打开文件的数量 | 5000 |
maxWriteAheadLogSize | 寫前日志寫入強制刷新前的最大大小 | 0 (=動態選擇) |
statistics | 如果非nil,則會收集數據庫操作的度量 | nil |
disableDataSync | manifest和數據文件的內容不會同步到穩定存儲 | false |
useFSync | 每次將存儲發到穩定存儲時都會發起fsync | false |
maxLogFileSize | 資訊日誌文件的最大大小,超出則會旋轉 | 0 (=所有日志都寫入一個文件) |
logFileTimeToRoll | 資訊日志文件旋轉的時間(單位:秒) | 0 (禁用) |
keepLogFileNum | 要保留的資訊日誌文件的最大數量 | 1000 |
bytesPerSync | 在寫入時逐漸將文件同步到磁盤 | 0 (禁用) |
ObjectiveRocks 列族选项
选项 | 描述 | 默认值 |
---|---|---|
comparator | 用於定義表中鍵的順序 | 字節卻序的字典順序 |
mergeOperator | 對合併操作必須提供 | nil |
writeBufferSize | 在寫入磁盤之前在記憶體中建築的數據量 | 4 * 1048576 (4MB) |
maxWriteBufferNumber | 在記憶體中建築的寫入緩冲板數量的最大值 | 2 |
minWriteBufferNumberToMerge | 寫入存儲之前合併的寫入緩冲板的最小數量 | 1 |
compressionType | 使用指定的壓縮算法進行塊壓縮 | Snappy 壓縮 |
prefixExtractor | 如果非nil,則使用指定的函數來確定鍵的前綴 | nil |
numLevels | DB的層數 | 7 |
level0FileNumCompactionTrigger | 使用指定的壓縮算法進行塊壓縮 | 4 |
level0SlowdownWritesTrigger | level-0文件數量的軟限制 | 20 |
level0StopWritesTrigger | level-0文件數量的最大值 | 24 |
targetFileSizeBase | 収縮的目標文件大小 | 2 * 1048576 (2MB) |
targetFileSizeMultiplier | 不同層次文件大小的倍數器 | 1 (不同層次的文件將具有相似的大小) |
maxBytesForLevelBase | 控制某個層次的最大總數據大小 | 10 * 1048576 (10MB) |
maxBytesForLevelMultiplier | 文件大小/層次的倍數器 | 10 |
expandedCompactionFactor | 所有収縮文件中的最大字節數 | 25 |
sourceCompactionFactor | 在單次收縮運行中要収縮的所有源文件的 最大字節數 | 1 |
maxGrandparentOverlapFactor | 控制父代(即level+2)中最大重叠字節數 | 10 |
softRateLimit | 當任何層次的收縮分數超過此限制時,將延遲0-1毫秒的PUT操作 | 0 (禁用) |
hardRateLimit | 当任何级别的压缩得分超过此限制时,put操作将延迟1ms。 | 0 (禁用) |
arenaBlockSize | 区域能够分配内存的一个块的大小。 | 0 |
disableAutoCompactions | 禁用自动压缩。 | false |
purgeRedundantKvsWhileFlush | 在将内存表刷新到存储时清除重复键或删除的键。 | true |
verifyChecksumsInCompaction | 如果设置为true,压缩时将验证每个读取操作的校验和(作为压缩的一部分)。 | true |
filterDeletes | 当此选项为true时,使用KeyMayExist API过滤删除操作。 | false |
maxSequentialSkipInIterations | 在迭代中如果不设置此选项,跳过连续的相同用户键。 | 8 |
memTableRepFactory | 提供一个MemTableRep对象的工厂。 | nil 。内部,RocksDB将使用一个提供一个基于跳表实现的MemTableRep工厂的工厂。 |
tableFacotry | 提供一个TableFactory对象的工厂。 | nil 。内部,RocksDB将使用一个提供默认TableBuilder和TableReader实现(使用默认的BlockBasedTableOptions)的基于块的表工厂。 |
memtablePrefixBloomBits | 如果设置了prefixExtractor且bloom_bits不为0,对内存表创建前缀布隆。 | 0 |
memtablePrefixBloomProbes | 每个键的哈希探测数。 | 6 |
memtablePrefixBloomHugePageTlbSize | 用于内存表中bloom的巨大页面TLB的页面大小。 | 0 |
bloomLocality | 控制布隆过滤器探测的局部性,以改善缓存未命中率。 | 0 |
maxSuccessiveMerges | 在内存表中键上的最大连续合并操作数。 | 0 |
minPartialMergeOperands | 积累的局部合并操作数,达到此数量后执行局部合并。 | 2 |
读取选项
选项 | 描述 | 默认值 |
---|---|---|
verifyChecksums | 读取的数据将与相应的校验和进行验证。 | true |
fillCache | 是否将此迭代的读取操作缓存到内存中。 | true |
写入选项
选项 | 描述 | 默认值 |
---|---|---|
syncWrites | 在被视为完成之前,将从缓冲区刷新写入。 | false |
disableWriteAheadLog | 写入将不会首先写入写入日志。 | true |
ignoreMissingColumnFamilies | 忽略写入不存在的列族。 | false |
表格式
BlockBasedTable
:是RocksDB的默认SST表格式。PlainTable
:是RocksDB的SST文件格式,针对降低纯内存或低延迟媒体的查询延迟进行了优化。CuckooTable
:专为需要快速点查找但不需要快速范围扫描的应用而设计。
Memtable Formats
SkipList
:使用跳表存储键。这是默认选项。Vector
:创建由 std::vector 支持的 MemTableReps。在迭代时,向量会被排序。这对于迭代很少而写操作一般不会在读取开始后执行的工作负载非常有用。HashSkipList
:包含一个指向跳表的固定桶数组。HashLinkedList
:基于散列表创建内存表:它包含一个指向固定桶数组的指针,每个桶内部包含一个或多个超过预定义阈值的链表或跳表。Cuckoo
:创建基于布隆哈希的内存表示。布隆哈希是一种闭哈希策略,其中所有键/值对都存储在桶数组本身中,而不是存储在桶数组以外的某些数据结构中。
更多详细信息,请访问维基百科 基于哈希的内存表实现