记录是Aerospike表示存储在数据库中数据的形式。记录由元数据和多个bin组成。这些bin保存记录的数据。每个bin有一个名称与一个值。元数据是关于记录的附加信息。在数据库中使用键(key)查找记录。
通过下列函数之一可初始化一条记录:
as_record_inita()
— 在栈上初始化一条记录及其bin。as_record_init()
— 在栈上初始化一条记录,但在堆上分配bin。as_record_new()
— 在堆上分配一条记录及其bin并初始化。无论何时初始化的记录,不再使用时应通过as_record_destroy()释放资源。
as_record_inita()与as_record_init()都在栈上分配且初始化一个记录,但它们分配记录bin的行为不同。
as_record_inita()
在栈上分配bin。as_record_init()
在堆上分配bin。下面是一个简单的as_record_inita()例子。在使用上没有区别,只是在如何分配空间上存在不同。
as_record rec;
as_record_inita(&rec, 3);
as_record_set_int64(&rec, 1);
as_record_set_int64(&rec, 2);
as_record_set_int64(&rec, 3);
as_record_destroy(&rec);
即使记录和bin都是在栈上分配,bin值所用空间还是可能会从堆上分配。因此,应使用as_record_destroy()安全地释放记录及其相关资源。
使用as_record_new()将在堆上分配记录。
as_record *rec = as_record_new(10);
as_record_set_int64(rec, 1);
as_record_set_int64(rec, 2);
as_record_set_int64(rec, 3);
as_record_destroy(rec);
当不再需要此记录时,应使用as_record_destroy()安全地释放记录及其相关资源。
API提供多种方法来访问记录的bin。
为访问记录的bin,首先需要初始化一条记录并以bin数据填充。有两种获取记录数据的方法:
一旦有个初始化完成的记录,就可使用这些功能之一,读取记录的bin数据。
API提供了一系列getter函数,从记录中取出指定数据类型的bin数值。getter函数要求一个记录对象与bin名称做为参数。
下面的getter函数用于获取bin的原生类型(native-type)数值:
as_record_get_int64()
as_record_get_str()
更详细内容在【API文档】。
以下是getter函数使用示例:
int64_t ibin = as_record_get_int64(rec, "ibin", 123);
char *sbin = as_record_get_str(rec, "sbin");
下面的getter函数返回非原生类型数值的指针:
as_record_get_integer()
as_record_get_string()
as_record_get_bytes()
as_record_get_list()
as_record_get_map()
若应用保存这些getter函数返回的数值指针,然后销毁了这条记录,那么指针将指向无效数据。为防止出现这种情况,可通过as_val_reserve()增加这些getter函数返回值的引用计数。
as_list *lbin = (as_list*)as_val_reserve(as_record_get_list(&rec, "lbin"));
as_record_destroy(&rec);
int64_t i1 = as_arraylist_get_int64(lbin, 1);
int64_t i2 = as_arraylist_get_int64(lbin, 2);
int64_t i3 = as_arraylist_get_int64(lbin, 3);
as_list_destroy(lbin);
上面代码中的5-7行会有效地读取数据。若as_val_reserve()没被调用,就会引起无效读取,可能导致数据损坏。完成数据读取后,应使用相应的销毁函数释放它。
在能填充一条记录数据前,必须先初始化它。有三个初始化记录的方法。
as_record_inita()
— 在栈上初始化一条记录及其bin。as_record_init()
— 在栈上初始化一条记录,但在堆上分配bin。as_record_new()
— 在堆上分配一条记录及其bin并初始化。这些函数都接受一个参数指明需分配bin的个数,初始化完成的记录能用来填充数据。
有一系列的setter函数,用来设置不同数据类型的bin。每个setter函数要求一个记录对象、一个bin名称和一个bin值做为参数,操作成功返回true。
下面是设置原生类型bin数据的setter函数:
as_record_set_int64()
— 设置一个int64_t类型的值。as_record_set_str()
— 设置值为一个以空字符(NULL)结束的字符串。as_record_set_strp()
— 设置值为一个以空字符(NULL)结束的字符串,指定在记录销毁时是否释放原值所占用的空间。as_record_set_raw()
— 设置一个字节数组类型的值as_record_set_rawp()
— 设置一个字节数组类型的值,指明在记录销毁时是否释放原值所占用的空间。具体细节请参见【API文档】。
下面是一些使用setter函数的例子:
as_record_set_int64(rec, "ibin", 123);
as_record_set_str(rec, "sbin", "abc");
as_record_set_strp(rec, "spbin", strdup("ijk"), true);
as_record_set_raw(rec, "rbin", (uint8_t*)"xyz", 3);
下列setter函数保持对非原生类型数据的指针引用:
as_record_set_integer() — Sets an as_integer value.
as_record_set_string() — Sets an as_string value.
as_record_set_bytes() — Sets an as_bytes value.
as_record_set_list() — Sets an as_list value.
as_record_set_map() — Sets an as_map value.
当通过as_record_destroy()释放一个记录,使用这些调用设置的值也将被释放。若在其它地方使用这些值,在向记录设置这些值时应用通过as_val_reserver()增加其引用计数,防止它们在释放记录时被同时释放。
下面是在将值增加到记录前增加其引用计数的示例,当记录被销毁时,list将不受影响。若引用计数未被增加,那么list将被销毁,其内包含的数据也不再存在。
as_arraylist list;
as_arraylist_init(&list, 3);
as_arraylist_append_int64(&list, 1);
as_arraylist_append_int64(&list, 2);
as_arraylist_append_int64(&list, 3);
as_record rec;
as_record_inita(&rec, 1);
as_record_set_list(&rec, "lbin", (as_list*)as_val_reserve(&list));
as_record_destroy(&rec);
int64_t i1 = as_arraylist_get_int64(&list, 1);
int64_t i2 = as_arraylist_get_int64(&list, 2);
int64_t i3 = as_arraylist_get_int64(&list, 3);
as_arraylist_destroy(&list);
上面代码中的13-15行会有效地读取数据。若as_val_reserver()未被 调用,就会是无效的读取,可能导致数据损坏。
分代编号即一条记录的版本号。每次对记录的修改都会增加分代编号的值。可设置一条记录的分代编号,但通常用来提示记录所在的服务器一个期望的分代编号。
rec->gen = 0
每条记录还有一个生存时间(TTL),指定记录何时过期或从数据库中驱逐。此值定义从当前开始的秒数。
rec->ttl = 3600 * 24;
你可能需要遍历一条记录的所有bin,Aerospike C客户端提供两个方法:
as_record_foreach()
— 迭代一条记录的每一个bin,并为每个bin调用一函数。as_record_iterator()
— 记录全部bin的迭代器。函数as_record_foreach()迭代一条记录的每一个bin,并为每个bin调用一函数。此函数还接受一个用户数据参数,可以是用户提供的、在回调函数内使用的任何数据。
下面的例子填充一个记录的数据,然后迭代遍历它的全部bin。
as_record rec;
as_record_inita(&rec, 3);
as_record_set_int64(&rec, "a", 1);
as_record_set_int64(&rec, "b", 2);
as_record_set_int64(&rec, "c", 3);
as_record_foreach(&rec, callback, NULL);
这个例子使用的回调函数打印bin的名称和数值:
bool callback(const char *name, const as_val *value, void *udata)
{
as_integer *ivalue = as_integer_fromval(value);
if (ivalue) {
printf("%s = %d\n", name, as_integer_get(ivalue));
}
else {
printf("%s is not an integer?!\n", name);
}
return true;
}
若回调函数返回true,继续迭代下一个bin,否则迭代中止。
as_record_iterator是一数据结构,提供迭代一条记录全部bin的能力。为使用as_record_iterator,首先需要初始化它:
as_record_iterator_init()
— 初始化一个栈上分配的迭代器。as_record_iterator_new()
— 分配和初始化一个堆上分配的迭代器。一旦迭代器初始化完成,就能使用下面的函数完成迭代器遍历:
as_record_iterator_has_next()
— 检测是否还有更多的bin可遍历。as_record_iterator_next()
— 将迭代器移动到下一个bin,并返回此bin。下面的示例,是前面foreach示例的迭代器实现方式:
as_record_iterator it;
as_record_iterator_init(&it, &rec);
while (as_record_iterator_has_next(&it)) {
as_bin *bin = as_record_iterator_next(&it);
char *name = as_bin_get_name(bin);
as_val *value = (as_val*)as_bin_get_value(bin);
as_integer *ivalue = as_integer_fromval(value);
if (ivalue) {
printf("%s = %d\n", name, as_integer_get(ivalue));
}
else {
printf("%s is not an integer?!\n", name);
}
}
读取操作从服务器取回数据并填充记录对象。下面是一些从服务器上读取记录数据的操作。
aerospike_key_get()
— 读取一条记录的全部bin。在【读取记录】章节进一步讨论。aerospike_key_select()
— 读取一条记录的指定bin。在【读取记录】章节进一步讨论。aerospike_key_operate()
— 在一条记录上执行操作,包括读取指定bin。在【读取记录】章节进一步讨论。每个操作接受一个记录对象作为参数(as_record **),用来接收从服务器读取的数据来。
下面解释一个记录对象如何被读取操作所填充。
若记录对象参数是一个空指针(NULL),则读取操作会从堆上分配记录的空间,并且用足够多的bin个数初始化它,以容纳服务器返回的全部bin数据。
as_record *rec = NULL;
aerospike_key_get(&as, &err, NULL, &key, &rec)
as_record_destroy(rec);
当不再需要此记录对象时,必须通过as_record_destroy()释放其资源。
初始化完成的记录被用作读取操作的参数。
若记录对象是以非零的bin个数初始化,读操作尝试以记录可用的bin尽可能多地填充它。作为一个例子,比如说初始化10个bin的一个记录对象,若服务器返回3个bin的数据,那么对象记录只有3个bin会被填充值;若服务器返回20个bin的数据,那么只有前10个bin数据会被填充到记录对象中。或者,若记录对象的10个bin只有5个bin可用,将它传送给读操作,那么只有这5个bin被来自服务器的数据填写。
若记录对象被初始化成没有bin,那读取操作将尝试从堆上分配足够多的bin空间,以容纳服务器端返回的全部bin数据。
在初始化记录对象时,可选择在栈上或堆上初始化它:
as_record_inita()
— 在栈上初始化一条记录及其bin。as_record_init()
— 在栈上初始化一条记录,但在堆上分配bin。as_record_new()
— 在堆上分配一条记录及其bin并初始化。