摘要:
DPN作为PACK的元数据,对下用于访问具体的PACK,对上形成知识网格,在整个逻辑关系中,DPN的数据对于数据的访问起到了中枢的作用。
本文对DPN的数据结构的使用关系做说明。
DPN的数据成员:
uint8_t used : 1; // occupied or not
uint8_t local : 1; // owned by a write transaction, thus to-be-commit
uint8_t synced : 1; // if the pack data in memory is up to date with the
// version on disk
uint8_t null_compressed : 1;
uint8_t data_compressed : 1;
uint8_t no_compress : 1;
uint8_t padding[3];
uint32_t base; // index of the DPN from which we copied, used by local pack
uint64_t addr; // data start address
uint64_t len; // data length
uint32_t nr; // number of records
uint32_t nn; // number of nulls
common::TX_ID xmin; // creation trx id
common::TX_ID xmax; // delete trx id
union {
int64_t min_i;
double min_d;
char min_s[8];
};
union {
int64_t max_i;
double max_d;
char max_s[8];
};
union {
int64_t sum_i;
double sum_d;
uint64_t maxlen;
};
核心成员解释:
- addr: 指向打开的DATA文件的偏移量, 是本PACK的起始位置。 通过addr来定位在文件中的位置
- len: PACK的长度, 用于读取PACK时
- xmin: 在创建时的事务ID
- xmax: 名字起做最大的事务ID,但是应当理解为本DPN指向的DPN。
- 这种设计策略可以参考postgres的MVCC的版本控制机制
- DPN和PACK实现了MVCC, 每个DPN中的最大的事务ID就是本DPN所指向的版本
成员-标记的PACK地址:
std::atomic - C++中文 - API参考文档
内存模型 - C++中文 - API参考文档
std::memory_order - C++中文 - API参考文档
// a tagged pointer, 16 bits as ref count.
// Only read-only dpn uses it for ref counting; local dpn is managed only by
// one write session
std::atomic_ulong tagged_ptr;
uint64_t GetPackPtr() const { return tagged_ptr.load(); }
void SetPackPtr(uint64_t v) { tagged_ptr.store(v); }
语义解释:
认为是当前使用的PACK, 需要通过更多的上下文来确定逻辑
IncRef
std::atomic_ref<T>::compare_exchange_weak, std::atomic_ref<T>::compare_exchange_strong - C++中文 - API参考文档
bool IncRef() {
auto v = tagged_ptr.load();
while (v != 0 && v != loading_flag)
if (tagged_ptr.compare_exchange_weak(v, v + tag_one)) return true;
return false;
}
RCAttr::LoadDataPackS
void RCAttr::LoadDataPackS(size_t pi, loader::ValueCache *nvs) {
auto &dpn(get_dpn(pi));
auto load_nulls = Type().NotNull() ? 0 : nvs->NumOfNulls();
auto cnt = nvs->NumOfValues();
// no need to store any values - uniform package
if (load_nulls == cnt && (dpn.nr == 0 || dpn.NullOnly())) {
dpn.nr += cnt;
dpn.nn += cnt;
return;
}
// new package or expanding so-far-null package
if (dpn.nr == 0 || dpn.NullOnly()) {
auto sp = ha_rcengine_->cache.GetOrFetchObject<Pack>(get_pc(pi), this);
dpn.SetPackPtr(reinterpret_cast<unsigned long>(sp.get()) + tag_one);
}
get_packS(pi)->LoadValues(nvs);
}
CAS
bool CAS(uint64_t &expected, uint64_t desired) { return tagged_ptr.compare_exchange_weak(expected, desired); }
std::atomic_ref<T>::compare_exchange_weak
原子地比较被引用对象的值表示与
expected
的值表示,而若它们逐位相等,则以 desired
替换前者(进行读修改写操作)。否则,加载存储于被引用对象的实际值到 expected
中(进行加载操作)。读修改写和加载操作的内存模型分别是
success
和 failure
。在 (2) 和 (4) 版本中, order
同时用于读修改写操作和加载操作,除了若 order == std::memory_order_acq_rel 或 order == std::memory_order_release ,则分别将 std::memory_order_acquire 和 std::memory_order_relaxed 用于加载操作。参数
expected-到期待在
atomic_ref
所引用对象中找到的值的引用desired-若满足期待则要存储于被引用对象中的值success-若比较成功则用于读修改写操作的内存同步顺序。容许所有值。failure-若比较失败则用于加载操作的内存同步顺序。不能为 std::memory_order_release 或 std::memory_order_acq_relorder-两个操作的内存同步顺序返回值
若成功更改被引用数据则为 true ,否则为 false 。
注解
比较和复制是逐位的(类似 std::memcmp 和 std::memcpy );不使用构造函数、赋值运算符或比较运算符。
允许弱形式 (1-2) 虚假地失败,即表现为 *this != expected ,即使它们相等。比较并交换在循环中时,弱版本在某些平台上将产生较好的性能。
弱比较并交换会要求循环,而强版本不会要求时,最好用强版本,除非
T
的对象表示可能包含陷阱位,或相同值有多种对象表示(例如浮点 NaN )。那些情况下,弱比较并交换通常能用,因为它在某些稳定的对象表示上快速收敛。若有参与 union 某些成员,但非其他成员的值表示的位,则比较并交换可能始终失败,因为这种填充位在不参与活跃成员的值表示时拥有不确定值。
忽略决不参与对象值表示的填充位。