/* * Pointer to a location in the XLOG. These pointers are 64 bits wide, * because we don't want them ever to overflow. */
typedef uint64 XLogRecPtr;
/* * Store the LSN as a single 64-bit value, to allow atomic loads/stores. * * For historical reasons, the storage of 64-bit LSN values depends on CPU * endianness; PageXLogRecPtr used to be a struct consisting of two 32-bit * values. When reading (and writing) the pd_lsn field from page headers, the * caller must convert from (and convert to) the platform's native endianness. */ typedefstruct { uint64 lsn; } PageXLogRecPtr;
/* * Generate a WAL segment file name. Do not use this function in a helper * function allocating the result generated. */ staticinlinevoid XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes) { snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)), (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes))); }
An example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
gujinfei@jeff:~/codes/blink-tree-cpp/build$ pg_controldata $PGDATA | grep "Bytes per WAL segment" Bytes per WAL segment: 16777216 gujinfei@jeff:~/codes/blink-tree-cpp/build$
CREATE TABLE pred(n numeric, s text); INSERT INTO pred(n) SELECT n FROM generate_series(1,10000) n; CREATE INDEX ON pred(n) WITH (fillfactor =10); ANALYZE pred;
mytest=# BEGIN ISOLATION LEVEL SERIALIZABLE; BEGIN mytest=*# EXPLAIN (analyze, costs off, timing off, summary off) SELECT*FROM pred WHERE n BETWEEN1000AND1001; QUERY PLAN ------------------------------------------------------------------- Index Scan using pred_n_idx on pred (actual rows=2.00 loops=1) Index Cond: ((n >='1000'::numeric) AND (n <='1001'::numeric)) Index Searches: 1 Buffers: shared hit=1 read=2 Planning: Buffers: shared hit=6 (6rows)
mytest=*# SELECT relation::regclass, locktype, page, tuple FROM pg_locks WHERE mode ='SIReadLock'AND pid =512701ORDERBY1, 2, 3, 4; relation | locktype | page | tuple ------------+----------+------+------- pred | tuple |4|96 pred | tuple |4|97 pred_n_idx | page |28| (3rows)
mytest=*# EXPLAIN (analyze, costs off, timing off, summary off) SELECT*FROM pred WHERE n BETWEEN1000AND1002; QUERY PLAN ------------------------------------------------------------------- Index Scan using pred_n_idx on pred (actual rows=1002.00 loops=1) Index Cond: ((n >='1000'::numeric) AND (n <='1002'::numeric)) Index Searches: 1 Buffers: shared hit=15 (4rows)
Note the simplicity of the search, which behaves just as a nonconcurrent search, treating link pointers in exactly the same manner as any other pointer.
Note also that this procedure does no locking of any kind. This contrasts with conventional database search algorithms (e.g., Bayer and Schkolnick [3]), in which all searches read-lock the nodes they examine.
高地址 ------------------------- return address (to caller of main) ------------------------- saved rbp ------------------------- ← rbp (main) x (-0x8) y (-0xc) z (-0x10) padding ------------------------- ← rsp 低地址
执行 call 后:
1 2 3 4 5 6 7 8 9 10 11
高地址 ------------------------- return address to main caller ------------------------- saved rbp (main) ------------------------- ← rbp(main) local variables ------------------------- return address (0x100003fa8) ← rsp ------------------------- 低地址
八、add 函数栈帧
add 的 prologue:
1 2 3
pushq %rbp movq %rsp, %rbp movl %edi, -0x4(%rbp)
这里 没有 sub rsp。
该版本编译器没有显式为 add 分配额外栈空间。
本例中 add 为 leaf function。虽然未显式 sub rsp 分配空间,但由于使用了 push %rbp,局部变量仍然位于当前栈帧中,并未实际使用 red zone。 在 macOS / Linux 的 System V ABI 下:
栈顶以下 128 字节称为 red zone,可在 leaf function 中使用。
所以 add 是一个 leaf function:
没有再调用其他函数
不需要保持 16-byte 对齐给下一级
编译器优化掉 sub rsp
栈变为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
高地址 -------------------------------- main 的局部变量 -------------------------------- saved rbp (main) -------------------------------- return addr → main caller -------------------------------- return addr → main ← 8(%rbp_add) saved rbp (main) ← 0(%rbp_add) -------------------------------- ← rbp(add) local a copy local b copy local c -------------------------------- ← rsp 低地址
注意: 每次函数调用都会:
保存调用者 rbp
建立新的栈帧
形成一条链。
本例中 add 为 leaf function,未显式执行 sub rsp。 在 System V ABI 下允许使用 128 字节 red zone,因此编译器可省略栈空间分配。