From: Tomas Vondra Date: Sat, 4 Nov 2017 16:13:23 +0000 (+0100) Subject: Add gtm_snap.c comments (missing in a39b06b0c6) X-Git-Tag: XL_10_R1BETA1~92 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=cca8700e364c1031eb360de3ec16eba45152e01c;p=postgres-xl.git Add gtm_snap.c comments (missing in a39b06b0c6) These comments should have been included in a39b06b0c6, but I failed to include the file in the commit before pushing :-( --- diff --git a/src/gtm/main/gtm_snap.c b/src/gtm/main/gtm_snap.c index a331ed4189..9b769a1648 100644 --- a/src/gtm/main/gtm_snap.c +++ b/src/gtm/main/gtm_snap.c @@ -9,7 +9,79 @@ * * * IDENTIFICATION - * $PostgreSQL$ + * src/gtm/main/gtm_snap.c + * + * + * Functions in this source file manage transaction snapshots for global + * transactions, i.e. a list of transactions (GXIDs) a particular transaction + * sees as "running." The concept is mostly the same as in PostgreSQL (see + * GetSnapshotData in src/backend/storage/ipc/procarray.c for details), except + * that the snapshots are not computed on nodes but on GTM. + * + * The API is very simple as it consists of a single function: + * + * GTM_GetTransactionSnapshot + * + * that builds a snapshot and stores it in the main GTMTransactions array + * tracking all in-progress transactions. When multiple snapshot requests get + * grouped by GTM Proxy, we compute the snapshot only once and then use it + * for all transactions in the request. As computing the snapshot is quite + * expensive, this is a major benefit. + * + * There are also two functions handling the communication with GTM clients + * (either nodes or GTM proxies): + * + * ProcessGetSnapshotCommand + * ProcessGetSnapshotCommandMulti + * + * These functions are responsible for parsing of network messages, and then + * simply call GTM_GetTransactionSnapshot with the proper arguments. + * + * + * Memory management (GTM_SnapshotData) + * ------------------------------------ + * The snapshots are allocated in TopMostMemoryContext - we can't allocate + * them in per-thread contexts as the transactions may outlive the client + * connection (e.g. with prepared transactions). + * + * When building the snapshot, we use sn_xip from the first transaction (if + * it was already allocated), or a thread-local variable (multiple threads + * may be building snapshots at the same time). + * + * Once the snapshot is built, we copy it into the GTMTransaction array + * for each of the transactions passed to GTM_GetTransactionSnapshot. + * + * Snapshot for each transaction is stored in gti_current_snapshot in the + * global GTMTransactions array. We only need to allocate the sn_xip field, + * tracking the GXIDs of running transactions, and allocate it just once + * when the first transaction gets assigned to that slot, and then keep the + * buffer for all future transactions in the slot (until GTM shuts down). + * + * The sn_xip buffer is always allocated with space for the maximum number + * of GXIDSs, otherwise we might need to reallocate it. That means we need + * space for up to GTM_MAX_GLOBAL_TRANSACTIONS, which is currently 16384. + * Each GXID is 32 bits, so this means 64kB per GTMTransaction slot. There + * are GTM_MAX_GLOBAL_TRANSACTIONS slots, so this means 16k sn_xip buffers + * or 1GB of memory in total. + * + * XXX We may as well allocate all the memory at the very beginning - we + * will eventually allocate the same memory anyway (it only takes a few + * loops over GTMTransactions, so a few thousand transactions), and it + * would completely eliminate the palloc/pfree calls. + * + * XXX There's a memory leak in thr_snapshot - the memory is allocated in + * the global memory context, but we don't pfree it when the thread exits. + * We can either allocate it in per-thread context or statically (as a + * variable in the function). + * + * XXX While this eliminates the palloc/pfree calls, we still need to do + * a number of memcpy() calls when copying the built snapshot data into + * GTMTransaction for each of the transactions. Perhaps we should invent + * shapshots directly "shared" by multiple transactions. That is, keep the + * snapshots in a separate data structure (list?), track the number of + * transactions using it (refcount). And reuse it when refcount gets to 0 + * (after all the transactions either close or get a new snapshot). Not + * sure it's worth the additional complexity, though. * *------------------------------------------------------------------------- */ @@ -24,6 +96,9 @@ #include "gtm/pqformat.h" /* + * GTM_GetTransactionSnapshot + * Compute and store snapshot(s) for specified transactions. + * * Get snapshot for the given transactions. If this is the first call in the * transaction, a fresh snapshot is taken and returned back. For a serializable * transaction, repeated calls to the function will return the same snapshot. @@ -83,6 +158,10 @@ GTM_GetTransactionSnapshot(GTM_TransactionHandle handle[], int txn_count, int *s /* * If the transaction does not exist, just mark the status field with * a STATUS_ERROR code + * + * FIXME This comment seems to be misplaced/stale - we're not checking + * if a transaction exists (we've already done that above and set the + * status to STATUS_NOT_FOUND). */ if ((mygtm_txninfo != NULL) && (snapshot == NULL)) snapshot = &mygtm_txninfo->gti_current_snapshot;