持久性内存编程——类型

    xiaoxiao2022-07-03  114

    在之前的所有关于持久化内存编程的文章中,代码片段和示例都有持久指针(pmemoid),没有任何类型信息——它们是简单的C结构。在pmem库开发的早期,开发者发现使用类似的东西非常容易出错,而且通常很困难。他们在用类型安全容器封装pmemoids时付出了相当大的努力,最终结果可以与C++11中的SydDypTr等进行比较,之后的所有内容将只使用类型安全特性。

    目录

    布局声明

    类型化持久指针

    PMEMoid和TOID操作

    运行时类型安全

    用例


    布局声明

    所有使用pmemobj的持久内存程序都应该有一个明确定义的内存布局,最好是在自己的文件中进行布局的定义。为了提供运行时和编译时类型的安全性,除了声明结构之外,还需要使用特殊的宏。例如,我们的字符串存储示例的布局如下所示:

    POBJ_LAYOUT_BEGIN(string_store); POBJ_LAYOUT_ROOT(string_store, struct my_root); POBJ_LAYOUT_END(string_store); #define MAX_BUF_LEN 10 struct my_root { char buf[MAX_BUF_LEN]; };

    现在可以在代码中使用类型化的持久指针。此代码中的字符串存储只是一个名称,创建或打开具有特定布局的池时,建议使用pobj_layout_name宏,如下所示:

    pmemobj_create(path, POBJ_LAYOUT_NAME(string_store), PMEMOBJ_MIN_POOL, 0666); ... pmemobj_open(path, POBJ_LAYOUT_NAME(string_store));

    如果你觉得所有这些都令人困惑,请先阅读这篇文章( this ),这对该内容有深入解释。

    类型化持久指针

    使用以下构造来代替pmemoids指针:

    TOID(struct my_root) root;

    要取消引用,不再需要将另一个变量与pmemobj_direct结合使用,首选的方法是使用d_rw进行写入,使用d_ro进行读取。如下所示:

    if (D_RO(root)->buf[0] != 0) D_RW(root)->buf[0] = 0;

    大多数IDE都会正确地评估这些宏,并自动完成类型代码。

    PMEMoid和TOID操作

    一般来说,有两种类型的安全宏可以区分:在原始pmemoid上操作的宏(前缀为OID_),在类型TOID上操作的宏(前缀为TOID_)。

    所有pmemobj_函数只接受原始pmemoids作为参数。我们通常建议只使用宏,但如果需要将TOID“强制转换”为pmemoid,可以这样做:

    TOID(struct foo) data; pmemobj_direct(data.oid);

    所有没有TOID_或OID_前缀的宏通常都采用类型化指针,并将其作为结果返回(如POBJ_ROOT宏)。

    运行时类型安全

    布局中的每种类型都在内部分配了一个唯一的编号,然后可以用于验证。

    例如,对现有软件的更新可能改变了布局,如下所示:

    struct my_root_v1 { TOID(struct foo) data; } struct my_root_v2 { TOID(struct bar) data; }

    要检查布局的版本是否与现有对象对应,可以使用以下表达式:

    if (TOID_VALID(D_RO(root)->data)) { /* can use the data ptr safely */ } else { /* declared type doesn't match the object */ }

    如果不确定对象类型,也可以依赖嵌入的类型号,如:

    PMEMoid data; TOID(struct foo) foo; TOID(struct bar) bar; if (OID_INSTANCEOF(data, struct foo)) { TOID_ASSIGN(foo, data); } else if (OID_INSTANCEOF(data, struct bar)) { TOID_ASSIGN(bar, data); } else { /* error */ }

    与高级语言的相似性并非偶然。

    用例

    这是最后一次修改字符串存储示例。layout.h修改可以在上面看到。首先,从root对象开始。可以使用以下行,而不是首先使用pmemobj_root函数,然后使用pmemobj_direct作为实际指针:

    TOID(struct my_root) root = POBJ_ROOT(pop, struct my_root);

    还记得怎么保证代码会变短的吗?writer.c:

    TX_BEGIN(pop) { TX_MEMCPY(D_RW(root)->buf, buf, strlen(buf)); } TX_END

    因为不再有rootp了,这个也变得简单了,reader.c

    printf("%s\n", D_RO(root)->buf);

    完整代码:repository

    原文来自:http://pmem.io/2015/06/16/types.html

    最新回复(0)