持久性內存編程——類型

在之前的所有關於持久化內存編程的文章中,代碼片段和示例都有持久指針(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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章