Click one point on the canvas, then click another point — a straight line will appear.
Select the line → double-click the middle of the line → drag the new point: a curved effect will appear.
Flexible Control Over Line Arrows
When the endpoint of a line (especially an endpoint with an arrow) is connected to a shape, the default mode is “Connected Line” (automatic snapping). In this mode, the endpoint is “locked” to the shape’s boundary or center, and cannot be freely dragged.
Solution
Turn on Magnets
Select the target shape.
Menu Bar → Edit → Magnets → Show Magnets
You will see small red dots (magnets) appear around the shape.
These are the connectable positions.
Drag the endpoint of a line near the red dot, and it will snap/attach to that point.
What is Magnet?
Magnet (magnetic points) are those positions on the shape (Shape) that can attract the end points of the lines. When you draw a line with the Line Tool, endpoints that are close to these magnetic points will “snap” to it.
postgres@lavm-bar1guved6:/root$ pgbench -i test dropping old tables... NOTICE: table "pgbench_accounts" does not exist, skipping NOTICE: table "pgbench_branches" does not exist, skipping NOTICE: table "pgbench_history" does not exist, skipping NOTICE: table "pgbench_tellers" does not exist, skipping creating tables... generating data (client-side)... vacuuming... creating primary keys... done in1.54 s (drop tables 0.11 s, create tables 0.49 s, client-side generate 0.54 s, vacuum 0.18 s, primary keys 0.23 s). postgres@lavm-bar1guved6:/root$ pgbench -T 30 test pgbench (19devel) starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 1 number of threads: 1 maximum number of tries: 1 duration: 30 s number of transactions actually processed: 3522 number of failed transactions: 0 (0.000%) latency average =<strong>8.518</strong> ms initial connection time=4.025 ms tps =<strong>117.400485</strong> (withoutinitial connection time)
postgres@lavm-bar1guved6:/root$ psql test psql (19devel) Type "help" for help. test=# ALTERSYSTEMSET synchronous_commit = off; ALTERSYSTEM test=# SELECT pg_reload_conf(); pg_reload_conf ---------------- t (1row) postgres@lavm-bar1guved6:/root$ pgbench -T 30 test pgbench (19devel) starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 1 number of threads: 1 maximum number of tries: 1 duration: 30 s number of transactions actually processed: 9510 number of failed transactions: 0 (0.000%) latency average =<strong>3.154</strong> ms initial connection time=4.383 ms tps =<strong>317.038330</strong> (withoutinitial connection time)
服务器启动时,第一个启动的进程是 postmaster(新版本为postgres)。postmaster 接着会生成 startup process(启动进程),startup process 负责在发生故障时进行数据恢复。
startup process 是一个短暂的、一次性的进程,它的主要职责是在数据库启动时执行崩溃恢复或归档恢复。它完成它的工作后,就会退出。
1 2 3
postgres@lavm-bar1guved6:/root$ pg_controldata -D /home/postgres/pgdata/ |grep state Database cluster state: in production postgres@lavm-bar1guved6:/root$
postgres@lavm-bar1guved6:/root$ pg_ctl stop -m immediate waiting for server to shut down.... done server stopped postgres@lavm-bar1guved6:/root$ pg_controldata -D /home/postgres/pgdata/ |grep state Database cluster state: in production
当我们启动服务器时,启动进程会检测到之前发生了故障,因而进入恢复模式:
1 2 3 4 5 6 7 8 9 10 11
2025-08-04 10:23:31.860 CST [487414] LOG: starting PostgreSQL 19devel on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit 2025-08-04 10:23:31.861 CST [487414] LOG: listening on IPv4 address "127.0.0.1", port 5432 2025-08-04 10:23:31.878 CST [487414] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432" 2025-08-04 10:23:31.920 CST [487420] LOG: database system was interrupted; last known up at 2025-08-01 09:36:11 CST 2025-08-04 10:23:32.098 CST [487420] LOG: database system was not properly shut down; automatic recovery in progress 2025-08-04 10:23:32.125 CST [487420] LOG: redo starts at 0/01B75168 2025-08-04 10:23:32.125 CST [487420] LOG: invalid record length at 0/01B752A8: expected at least 24, got 0 2025-08-04 10:23:32.125 CST [487420] LOG: redo done at 0/01B75270 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.01 s 2025-08-04 10:23:32.132 CST [487418] LOG: checkpoint starting: end-of-recovery fast wait 2025-08-04 10:23:32.152 CST [487418] LOG: checkpoint complete: wrote 0 buffers (0.0%), wrote 3 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.006 s, sync=0.005 s, total=0.022 s; sync files=2, longest=0.005 s, average=0.003 s; distance=0 kB, estimate=0 kB; lsn=0/01B752A8, redo lsn=0/01B752A8 2025-08-04 10:23:32.155 CST [487414] LOG: database system is ready to accept connections
typedefstructLWLock { uint16 tranche; /* tranche ID */ pg_atomic_uint32 state; /* state of exclusive/nonexclusive lockers */ proclist_head waiters; /* list of waiting PGPROCs */ #ifdef LOCK_DEBUG pg_atomic_uint32 nwaiters; /* number of waiters */ structPGPROC *owner; /* last exclusive owner of the lock */ #endif } LWLock;
tranche 每个 LWLock 都属于某个 tranche,tranche 是一个 int 类型的 ID,代表这把锁的用途
state bit0~23:共享锁状态,实际最多用bit0~17,因为backend最多18位 bit24: 排他锁状态 bit28:用于锁定等待队列:waiters bit29: 是否允许唤醒等待队列里面的进程,初始状态:LW_FLAG_RELEASE_OK bit30: LW_FLAG_HAS_WAITERS :是否有waiter
waiters 等待队列
二 Interface说明
2.1 LWLockAcquire
加锁,失败进入等待队列,直接加上锁的情况,可能会造成等待队列无效唤醒
acquire a lightweight lock in the specified mode Side effect: cancel/die interrupts are held off until lock release.
typedefstructLOCKTAG { uint32 locktag_field1; /* a 32-bit ID field */ uint32 locktag_field2; /* a 32-bit ID field */ uint32 locktag_field3; /* a 32-bit ID field */ uint16 locktag_field4; /* a 16-bit ID field */ uint8 locktag_type; /* see enum LockTagType */ uint8 locktag_lockmethodid; /* lockmethod indicator */ } LOCKTAG;
/* * disk page organization * * space management information generic to any page * * pd_lsn - identifies xlog record for last change to this page. * pd_checksum - page checksum, if set. * pd_flags - flag bits. * pd_lower - offset to start of free space. * pd_upper - offset to end of free space. * pd_special - offset to start of special space. * pd_pagesize_version - size in bytes and page layout version number. * pd_prune_xid - oldest XID among potentially prunable tuples on page. * * The LSN is used by the buffer manager to enforce the basic rule of WAL: * "thou shalt write xlog before data". A dirty buffer cannot be dumped * to disk until xlog has been flushed at least as far as the page's LSN. * * pd_checksum stores the page checksum, if it has been set for this page; * zero is a valid value for a checksum. If a checksum is not in use then * we leave the field unset. This will typically mean the field is zero * though non-zero values may also be present if databases have been * pg_upgraded from releases prior to 9.3, when the same byte offset was * used to store the current timelineid when the page was last updated. * Note that there is no indication on a page as to whether the checksum * is valid or not, a deliberate design choice which avoids the problem * of relying on the page contents to decide whether to verify it. Hence * there are no flag bits relating to checksums. * * pd_prune_xid is a hint field that helps determine whether pruning will be * useful. It is currently unused in index pages. * * The page version number and page size are packed together into a single * uint16 field. This is for historical reasons: before PostgreSQL 7.3, * there was no concept of a page version number, and doing it this way * lets us pretend that pre-7.3 databases have page version number zero. * We constrain page sizes to be multiples of 256, leaving the low eight * bits available for a version number. * * Minimum possible page size is perhaps 64B to fit page header, opaque space * and a minimal tuple; of course, in reality you want it much bigger, so * the constraint on pagesize mod 256 is not an important restriction. * On the high end, we can only support pages up to 32KB because lp_off/lp_len * are 15 bits. */
typedefstructPageHeaderData { /* XXX LSN is member of *any* block, not only page-organized ones */ PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog * record for last change to this page */ uint16 pd_checksum; /* checksum */ uint16 pd_flags; /* flag bits, see below */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */ } PageHeaderData;