暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

openGauss WAL INSERT 128CAS无锁临界区保护

openGauss小助手 2021-10-22
1151

目前数据库或文件系统,WAL需要把内存中生成的日志信息插入到日志缓存中。为了实现日志高速缓存,日志管理系统会并发插入,通过预留全局位置来完成,一般使用两个64位的全局数据位置索引分别表示存储插入的起始和结束位置,最大能提供16EB(Exabyte)的数据索引的支持。为了保护全局的位置索引,WAL引入了一个高性能的原子锁实现每个日志缓存位置的保护,在NUMA架构中,特别是ARM架构中,由于原子锁退避和高跨CPU访问延迟,缓存一致性性能差异导致WAL并发的缓存保护成为瓶颈。

优化的主要涉及思想是将两个64位的全局数据位置信息通过128位原子操作替换原子锁,消除原子锁本身在跨CPU访问、原子锁退避(backoff)、缓存一致性代价。如图5-21所示。


图5-21 128CAS无锁临界区保护示意图

全局位置信息包括一个64位起始地址和一个64位的结束地址,将这两个地址合并成为一个128位信息,通过CAS原子操作完成免锁位置信息的预留。在ARM平台中没有实现128位的原子操作库,openGauss通过exclusive命令加载两个ARM64位数据来实现,ARM64汇编指令为LDXP/STXP。

关键数据结构及函数ReserveXLogInsertLocation的代码如下:

typedef union {

uint128 u128;

uint64 u64[2];

uint32 u32[4];

} uint128_u; /* 为了代码可读及操作,将u128设计成union的联合结构体,内存位置进行64位数值的赋值。 */

static void ReserveXLogInsertLocation(uint32 size, XLogRecPtr* StartPos, XLogRecPtr* EndPos, XLogRecPtr* PrevPtr)

{

volatile XLogCtlInsert* Insert = &t_thrd.shemem_ptr_cxt.XLogCtl->Insert;

uint64 startbytepos;

uint64 endbytepos;

uint64 prevbytepos;

size = MAXALIGN(size);

#if defined(__x86_64__) || defined(__aarch64__)

uint128_u compare;

uint128_u exchange;

uint128_u current;

compare = atomic_compare_and_swap_u128((uint128_u*)&Insert->CurrBytePos);

loop1:

startbytepos = compare.u64[0];

endbytepos = startbytepos + size;

exchange.u64[0] = endbytepos; /* 此处为了代码可读,将uint128设置成一个union的联合结构体。将起始和结束位置写入到exchange中。 */

exchange.u64[1] = startbytepos;

current = atomic_compare_and_swap_u128((uint128_u*)&Insert->CurrBytePos, compare, exchange);

if (!UINT128_IS_EQUAL(compare, current)) { /* 如果被其他线程并发更新,重新循环*/

UINT128_COPY(compare, current);

goto loop1;

}

prevbytepos = compare.u64[1];

#else

SpinLockAcquire(&Insert->insertpos_lck); /* 其余平台使用自旋锁原子锁来保护变量更新 */

startbytepos = Insert->CurrBytePos;

prevbytepos = Insert->PrevBytePos;

endbytepos = startbytepos + size;

Insert->CurrBytePos = endbytepos;

Insert->PrevBytePos = startbytepos;

SpinLockRelease(&Insert->insertpos_lck);

#endif /* __x86_64__|| __aarch64__ */

*StartPos = XLogBytePosToRecPtr(startbytepos);

*EndPos = XLogBytePosToEndRecPtr(endbytepos);

*PrevPtr = XLogBytePosToRecPtr(prevbytepos);

}

最后修改时间:2021-11-01 18:24:27
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论