Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1i9uH1-0006br-6P for pgsql-hackers@arkaria.postgresql.org; Mon, 16 Sep 2019 16:54:48 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1i9uGy-0007W5-VD for pgsql-hackers@arkaria.postgresql.org; Mon, 16 Sep 2019 16:54:45 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1i9uGy-0007Vu-CQ for pgsql-hackers@lists.postgresql.org; Mon, 16 Sep 2019 16:54:44 +0000 Received: from cyclops.postgrespro.ru ([93.174.131.138] helo=mail.postgrespro.ru) by magus.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1i9uGq-00022f-J8 for pgsql-hackers@postgresql.org; Mon, 16 Sep 2019 16:54:44 +0000 Received: from localhost (localhost [127.0.0.1]) by mail.postgrespro.ru (Postfix) with ESMTP id 6ADA021C3ED4; Mon, 16 Sep 2019 19:54:34 +0300 (MSK) X-Virus-Scanned: Debian amavisd-new at postgrespro.ru X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=x tagged_above=-99 required=4 WHITELISTED tests=[] autolearn=unavailable Received: from [192.168.27.223] (gw.postgrespro.ru [93.174.131.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client did not present a certificate) by mail.postgrespro.ru (Postfix) with ESMTPSA id 3DC2621C3ED3; Mon, 16 Sep 2019 19:54:33 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=postgrespro.ru; s=mail; t=1568652874; bh=U+fk2fjb4EiJZEe2rnede/h7exQNuHLhjrzI6ViFSmg=; h=Subject:To:Cc:References:From:Date:In-Reply-To; b=i4PPlXOB1q0MV0mfDhwyS57k6OISFd/b0sBe/Zj5cU6mRALLVkHh2+43RPvZ+4U5i dtI5FgGbxEGINnhfm+rEnkTvcsQhlIFYTW52UoN0lyNXfN4S2wSlBAyS73+hagx/ao kcaBtzhmPth9f9jhVC92/qnVb2Mp2a6nw4dA5jdA= Subject: Re: PATCH: logical_work_mem and logical streaming of large in-progress transactions To: Konstantin Knizhnik , Tomas Vondra Cc: Peter Eisentraut , Erik Rijkers , Masahiko Sawada , PostgreSQL Hackers References: <8940f374-6651-26d0-cefe-6c719454b6fe@2ndquadrant.com> <40c38758-04b5-74f4-c963-cf300f9e5dff@postgrespro.ru> <126e3a30-a7f5-ede4-2bd0-b217749c8b33@postgrespro.ru> <8eda5118-2dd0-79a1-4fe9-eec7e334de17@postgrespro.ru> <20190828190646.s3bjs22urff32k56@development> <20190829184824.kmrbchrk2ged6vjw@development> <322e40c4-8ca7-6c34-2544-28a6d95989c2@postgrespro.ru> From: Alexey Kondratov Message-ID: Date: Mon, 16 Sep 2019 19:54:32 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 MIME-Version: 1.0 In-Reply-To: <322e40c4-8ca7-6c34-2544-28a6d95989c2@postgrespro.ru> Content-Type: multipart/mixed; boundary="------------524DAFED047A6CA78CDF53FC" Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --------------524DAFED047A6CA78CDF53FC Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit >> >> FWIW my understanding is that the speedup comes mostly from >> elimination of >> the serialization to a file. That however requires savepoints to handle >> aborts of subtransactions - I'm pretty sure I'd be trivial to create a >> workload where this will be much slower (with many aborts of large >> subtransactions). >> Yes, and it was my main motivation to eliminate that extra serialization to file. I've experimented a bit with large transactions + savepoints + aborts and ended up with a following query (the same schema as before with 600k rows): BEGIN; SAVEPOINT s1; UPDATE large_test SET num1 = num1 + 1, num2 = num2 + 1, num3 = num3 + 1; SAVEPOINT s2; UPDATE large_test SET num1 = num1 + 1, num2 = num2 + 1, num3 = num3 + 1; SAVEPOINT s3; UPDATE large_test SET num1 = num1 + 1, num2 = num2 + 1, num3 = num3 + 1; ROLLBACK TO SAVEPOINT s3; ROLLBACK TO SAVEPOINT s2; ROLLBACK TO SAVEPOINT s1; END; It looks like the worst case scenario, as we do a lot of work and then abort all subxacts one by one. As expected,it takes much longer (up to x30) to process using background worker instead of spilling to file. Surely, it is much easier to truncate a file, than apply all changes + abort. However, I guess that this kind of load pattern is not the most typical for real-life applications. Also this test helped me to find a bug in my current savepoints routine, so new patch is attached. On 30.08.2019 18:59, Konstantin Knizhnik wrote: > > I think that instead of defining savepoints it is simpler and more > efficient to use > > BeginInternalSubTransaction + > ReleaseCurrentSubTransaction/RollbackAndReleaseCurrentSubTransaction > > as it is done in PL/pgSQL (pl_exec.c). > Not sure if it can pr > Both BeginInternalSubTransaction and DefineSavepoint use PushTransaction() internally for a normal subtransaction start. So they seems to be identical from the performance perspective, which is also stated in the comment section: /*  * BeginInternalSubTransaction  *        This is the same as DefineSavepoint except it allows TBLOCK_STARTED,  *        TBLOCK_IMPLICIT_INPROGRESS, TBLOCK_END, and TBLOCK_PREPARE states,  *        and therefore it can safely be used in functions that might be called  *        when not inside a BEGIN block or when running deferred triggers at  *        COMMIT/PREPARE time.  Also, it automatically does  *        CommitTransactionCommand/StartTransactionCommand instead of expecting  *        the caller to do it.  */ Please, correct me if I'm wrong. Anyway, I've performed a profiling of my apply worker (flamegraph is attached) and it spends the vast amount of time (>90%) applying changes. So the problem is not in the savepoints their-self, but in the fact that we first apply all changes and then abort all the work. Not sure, that it is possible to do something in this case. Regards -- Alexey Kondratov Postgres Professional https://www.postgrespro.com Russian Postgres Company --------------524DAFED047A6CA78CDF53FC Content-Type: application/zip; name="worker_aborts_perf.zip" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="worker_aborts_perf.zip" UEsDBBQACAAIAAeZME8AAAAAAAAAALb7CgAWACAAd29ya2VyX2Fib3J0c19wZXJmLnN2Z1VU DQAHb7N/XXOzf11vs39ddXgLAAEE6AMAAAToAwAA1L1tm9zGdSb8WfoVHe5mQ1pQE/VesCwn 0oiyuZEsPiRjO+t1cGG6MTMd9pvQaHImWf/35xwAhQZmQKAOqTBdviyJnOkG0Ker6rzd575/ 84+3m/XsbV4cVrvt14/YPH40O5TZdpmtd9v860fb3aN//O3nv/m77366eP2vL57NDm+vZy/+ 5dsfnl/MHn359OmfxMXTp9+9/m726o+/m7E5e/r02R8ezR7dlOX+10+fvnv3bv5OzHfF9dPf Fdn+ZrU4PIUXPsUXwpuewsUYmy/L5SO4BV658xzs0ezdalnewJ95DA91k6+ub8qvHyXMPprt tutdtvz60Wq7Kh/nb8snj2ZvV/m7b3e3Xz+KZ/EM3zKrXgmfbnv4euCB4BUxPkDzkl/frlfb N0MvZEmSPK1+i0/5d19+Oft+nW3y2TV+IrTV4g3c/HDM1qv/yEp4+vnsVZ7P8EIHuNL1qrw5 Xs4Xu83TyyIHu26vi/z6+ml1kcoqs6tdMVtnZX4onQGiGXwDs86zdN9aXesK3149wmF+U8JX iBfJb7PNfp0f5rMvv2ye9Q8/vX726tez+gfL/Oow++3nn/0GPk2eFXD35SrflrMVmPISPsd1 sTtul49mdwzMCP/hYHywT/23W179B97+2W8O5W4/w399uditd8XXj/5HXv0Pvpmrq0MOX5P6 +0ezpyOvvYxPr03ci3/ztP9g8MhP8ZlxdZR363xW3u1hTZb5bfl0cTjA9/HZ/Oq4XaTXv77Z gelm/wk3KnZv8l9fruHjfNX87ctqIf06nquvZotjcdgVv97vVtsyL76a/Q1uUV0b77EoVvuy e5N8scnqn1bf/V8uvvvm9Td/+fyzt1kxW+ZltlofotkBnnhxc1nCt7bJysVNvixvywh3ylef f4aPh4ti1i7V2X+CVZo3z76eLXeL4wY+6/w6L5+tc/zjt3fPl48fNS959GR+tSoO5cXNar2E C37W3m7szfWLHj3BN5weauwdzavqt+BeHHzt4du719n1H2DtwT1g8zz5S/zX00Ottvi2GH7w t88//+zp09lmdzzkX1ZfDa7P1fZq1zHJ4fF2t8zBIJ/haw83u3dwJXwNXOQ6LXcpfgf1a746 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 7oZODF1YjPf5bY3JqfA0v3mKNxu8cXVL1t4xiVn/ltz/loiZcRANcGv+N73/MYn3bHLNWZP+ uh88foK4Lfiav3Zf86/hjl/14S7woLWr+j/wjuknTn6pZ27QKPDMFSAEN4v7YbVxnpx+dSzb 38B+eNL5nPcyuIGPyx5+3NonUz7qx64Jh6PpronrWZUQfO2ygHuGqOsVfRssep/9VNVAHFLV WP1tWR7Smzzbp4vd/u6whhj3MQMfWAHAInQt/O+fwBNUr213NGPSILQOPoeWqt3W8Vyc9jRT py1dRYpMR9pEEj9hAdcAgxR31X+Gd3dtUqbgEZL6TkrN1Qcbdfbb1o5Pr/+rjPn26pAWebac PZY9GyZDNtRsrqsPJow4nYxo1veakPOIMxMxSbKhlnNl6jtZce4m/Mtx+2a7e7f9q9c6dK7F cua5CmM0nwYzkkwo3L62gp27BeFs3h0hTKpi+GfbdVZAlOhhzESyeb1MpBK+e1pEnLOIaYo1 EynnRtZ30me/IH+Xlz8e1+Xqz9mifL78sUpsD7PHpmtPZgbsqeKk2eBKq84GT8ZWZwL21JES FHsqxufK1ncyZ39G7q/TDBKp1aI6KdOjlukKDOnndjRvlqjmiecSFTzSPGKW5na0muvG7Yjk 3E0K6fdNU9kFM/bsyPXgsQlbndcLxp4OTjHqe3CrszjiNN8Tw17ndaSgkrM/On/40w+7xZuX +TrPIP15rHp7fPDMFKbxQN0zk83l2IJMIqMjUhiUyDawDODEhAS9uEtf/euri29++CGF/Z1d QRid3ryrCie02Eh2HPtEbGTg6JSRSD4wNpLn79nL7DrFvT57bHsrc9CEhuGxWH0w05qQjx6V GF7GYEJabGTkXDR3gqzgzE1Y7/BvyjKH9A//6LPLjdL4uR548tE404LPSYhxplHJXKpQPLkL NH96t82LJtCEs7Mq3L7EGSGvCB6ONvnAtuMuHbY6Y8QgCW4k5iKYKOl1kW0PWVXYe758frio 0Rm9n/qYVxoxTxrva3xjeoiWTBxJRTGvNHqe1CGFjs/+FFiuV4cyxZECrH14WZIxqZqSh/9C hZhJ20hxWuwp7ZzJUBbqN+v1bvEqL6v/giF115LCDm55yFfiB4tSjgdNKmJwpJLWJNxIzhMd yqJ8vn2brVcIk7nIymy9u361zfaHG7+KnLKmiZj8C3KSRYmIaKlmEs91HEo57iXs7W+PV1fg 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 --------------524DAFED047A6CA78CDF53FC Content-Type: text/x-patch; name="v2-0011-BGWorkers-pool-for-streamed-transactions-apply-wi.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="v2-0011-BGWorkers-pool-for-streamed-transactions-apply-wi.pa"; filename*1="tch" From 7ffeeb69fd626dbcc35ca13d97a8407573ea6d4a Mon Sep 17 00:00:00 2001 From: Alexey Kondratov Date: Wed, 28 Aug 2019 15:26:50 +0300 Subject: [PATCH v2 11/11] BGWorkers pool for streamed transactions apply without spilling on disk --- src/backend/postmaster/bgworker.c | 3 + src/backend/postmaster/pgstat.c | 3 + src/backend/replication/logical/proto.c | 17 +- src/backend/replication/logical/worker.c | 1783 +++++++++++----------- src/include/pgstat.h | 1 + src/include/replication/logicalproto.h | 4 +- src/include/replication/logicalworker.h | 1 + 7 files changed, 936 insertions(+), 876 deletions(-) diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index f5db5a8c4a..6860df07ca 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -129,6 +129,9 @@ static const struct }, { "ApplyWorkerMain", ApplyWorkerMain + }, + { + "LogicalApplyBgwMain", LogicalApplyBgwMain } }; diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index e5a4d147a7..b32994784f 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3637,6 +3637,9 @@ pgstat_get_wait_ipc(WaitEventIPC w) case WAIT_EVENT_HASH_GROW_BUCKETS_REINSERTING: event_name = "Hash/GrowBuckets/Reinserting"; break; + case WAIT_EVENT_LOGICAL_APPLY_WORKER_READY: + event_name = "LogicalApplyWorkerReady"; + break; case WAIT_EVENT_LOGICAL_SYNC_DATA: event_name = "LogicalSyncData"; break; diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c index 4bec9fe8b5..954ce7343a 100644 --- a/src/backend/replication/logical/proto.c +++ b/src/backend/replication/logical/proto.c @@ -789,14 +789,11 @@ logicalrep_write_stream_commit(StringInfo out, ReorderBufferTXN *txn, pq_sendint64(out, txn->commit_time); } -TransactionId +void logicalrep_read_stream_commit(StringInfo in, LogicalRepCommitData *commit_data) { - TransactionId xid; uint8 flags; - xid = pq_getmsgint(in, 4); - /* read flags (unused for now) */ flags = pq_getmsgbyte(in); @@ -807,8 +804,6 @@ logicalrep_read_stream_commit(StringInfo in, LogicalRepCommitData *commit_data) commit_data->commit_lsn = pq_getmsgint64(in); commit_data->end_lsn = pq_getmsgint64(in); commit_data->committime = pq_getmsgint64(in); - - return xid; } void @@ -823,13 +818,3 @@ logicalrep_write_stream_abort(StringInfo out, TransactionId xid, pq_sendint32(out, xid); pq_sendint32(out, subxid); } - -void -logicalrep_read_stream_abort(StringInfo in, TransactionId *xid, - TransactionId *subxid) -{ - Assert(xid && subxid); - - *xid = pq_getmsgint(in, 4); - *subxid = pq_getmsgint(in, 4); -} diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index ca632b7dc4..ab43b12985 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -92,11 +92,16 @@ #include "rewrite/rewriteHandler.h" #include "storage/bufmgr.h" +// #include "storage/condition_variable.h" +#include "storage/dsm.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lmgr.h" #include "storage/proc.h" #include "storage/procarray.h" +#include "storage/shm_mq.h" +#include "storage/shm_toc.h" +#include "storage/spin.h" #include "tcop/tcopprot.h" @@ -115,6 +120,54 @@ #include "utils/syscache.h" #define NAPTIME_PER_CYCLE 1000 /* max sleep time between cycles (1s) */ +#define PG_LOGICAL_APPLY_SHM_MAGIC 0x79fb2447 // TODO Consider change + +typedef struct ParallelState +{ + slock_t mutex; + // ConditionVariable cv; + bool attached; + bool ready; + bool finished; + Oid database_id; + Oid authenticated_user_id; + Oid subid; + Oid stream_xid; + uint32 n; +} ParallelState; + +typedef struct WorkerState +{ + TransactionId xid; + BackgroundWorkerHandle *handle; + shm_mq_handle *mq_handle; + dsm_segment *dsm_seg; + ParallelState volatile *pstate; +} WorkerState; + +/* Apply workers hash table (initialized on first use) */ +static HTAB *ApplyWorkersHash = NULL; +static WorkerState **ApplyWorkersIdleList = NULL; +static uint32 pool_size = 10; /* MaxConnections default? */ +static uint32 nworkers = 0; +static uint32 nfreeworkers = 0; + +/* Fields valid only for apply background workers */ +bool isLogicalApplyWorker = false; +volatile ParallelState *MyParallelState = NULL; + +/* Worker setup and interactions */ +static void setup_dsm(WorkerState *wstate); +static void setup_background_worker(WorkerState *wstate); +static void cleanup_background_worker(dsm_segment *seg, Datum arg); +static void handle_sigterm(SIGNAL_ARGS); + +static bool check_worker_status(WorkerState *wstate); +static void wait_for_worker(WorkerState *wstate); +static void wait_for_worker_to_finish(WorkerState *wstate); + +static WorkerState * find_or_start_worker(TransactionId xid, bool start); +static void stop_worker(WorkerState *wstate); typedef struct FlushPosition { @@ -143,47 +196,13 @@ bool MySubscriptionValid = false; bool in_remote_transaction = false; static XLogRecPtr remote_final_lsn = InvalidXLogRecPtr; -/* fields valid only when processing streamed transaction */ +/* Fields valid only when processing streamed transaction */ bool in_streamed_transaction = false; static TransactionId stream_xid = InvalidTransactionId; -static int stream_fd = -1; - -typedef struct SubXactInfo -{ - TransactionId xid; /* XID of the subxact */ - off_t offset; /* offset in the file */ -} SubXactInfo; - -static uint32 nsubxacts = 0; -static uint32 nsubxacts_max = 0; -static SubXactInfo * subxacts = NULL; -static TransactionId subxact_last = InvalidTransactionId; - -static void subxact_filename(char *path, Oid subid, TransactionId xid); -static void changes_filename(char *path, Oid subid, TransactionId xid); - -/* - * Information about subtransactions of a given toplevel transaction. - */ -static void subxact_info_write(Oid subid, TransactionId xid); -static void subxact_info_read(Oid subid, TransactionId xid); -static void subxact_info_add(TransactionId xid); - -/* - * Serialize and deserialize changes for a toplevel transaction. - */ -static void stream_cleanup_files(Oid subid, TransactionId xid); -static void stream_open_file(Oid subid, TransactionId xid, bool first); -static void stream_write_change(char action, StringInfo s); -static void stream_close_file(void); - -/* - * Array of serialized XIDs. - */ -static int nxids = 0; -static int maxnxids = 0; -static TransactionId *xids = NULL; +static TransactionId current_xid = InvalidTransactionId; +static TransactionId prev_xid = InvalidTransactionId; +static uint32 nchanges = 0; static bool handle_streamed_transaction(const char action, StringInfo s); @@ -199,6 +218,16 @@ static volatile sig_atomic_t got_SIGHUP = false; /* prototype needed because of stream_commit */ static void apply_dispatch(StringInfo s); +// /* Debug only */ +// static void +// iter_sleep(int seconds) +// { +// for (int i = 0; i < seconds; i++) +// { +// pg_usleep(1 * 1000L * 1000L); +// } +// } + /* * Should this worker apply changes for given relation. * @@ -250,6 +279,107 @@ ensure_transaction(void) return true; } +/* + * Look up worker inside ApplyWorkersHash for requested xid. + * Throw error if not found or start a new one if start=true is passed. + */ +static WorkerState * +find_or_start_worker(TransactionId xid, bool start) +{ + bool found; + WorkerState *entry = NULL; + + Assert(TransactionIdIsValid(xid)); + + /* First time through, initialize apply workers hashtable */ + if (ApplyWorkersHash == NULL) + { + HASHCTL ctl; + + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(TransactionId); + ctl.entrysize = sizeof(WorkerState); + ctl.hcxt = ApplyContext; /* Allocate ApplyWorkersHash in the ApplyContext */ + ApplyWorkersHash = hash_create("logical apply workers hash", 8, + &ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + } + + Assert(ApplyWorkersHash != NULL); + + /* + * Find entry for requested transaction. + */ + entry = hash_search(ApplyWorkersHash, &xid, HASH_FIND, &found); + + if (!found && start) + { + /* If there is at least one worker in the idle list, then take one. */ + if (nfreeworkers > 0) + { + char action = 'R'; + + Assert(ApplyWorkersIdleList != NULL); + + entry = ApplyWorkersIdleList[nfreeworkers - 1]; + if (!hash_update_hash_key(ApplyWorkersHash, + (void *) entry, + (void *) &xid)) + elog(ERROR, "could not reassign apply worker #%u entry from xid %u to xid %u", + entry->pstate->n, entry->xid, xid); + + entry->xid = xid; + entry->pstate->finished = false; + entry->pstate->stream_xid = xid; + shm_mq_send(entry->mq_handle, 1, &action, false); + + ApplyWorkersIdleList[--nfreeworkers] = NULL; + } + else + { + /* No entry in hash and no idle workers. Create a new one. */ + entry = hash_search(ApplyWorkersHash, &xid, HASH_ENTER, &found); + entry->xid = xid; + setup_background_worker(entry); + + if (nworkers == pool_size) + { + ApplyWorkersIdleList = repalloc(ApplyWorkersIdleList, pool_size + 10); + pool_size += 10; + } + } + } + else if (!found && !start) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_RESOURCES), + errmsg("could not find logical apply worker for xid %u", xid))); + else + elog(DEBUG5, "there is an existing logical apply worker for xid %u", xid); + + Assert(entry != NULL); + + return entry; +} + +/* + * Gracefully teardown apply worker. + */ +static void +stop_worker(WorkerState *wstate) +{ + /* + * Sending zero-length data to worker in order to stop it. + */ + shm_mq_send(wstate->mq_handle, 0, NULL, false); + + elog(LOG, "detaching DSM of apply worker #%u for xid %u", + wstate->pstate->n, wstate->xid); + dsm_detach(wstate->dsm_seg); + + /* Delete worker entry */ + (void) hash_search(ApplyWorkersHash, &wstate->xid, HASH_REMOVE, NULL); +} + /* * Handle streamed transactions. * @@ -262,12 +392,12 @@ static bool handle_streamed_transaction(const char action, StringInfo s) { TransactionId xid; + WorkerState *entry; /* not in streaming mode */ - if (!in_streamed_transaction) + if (!in_streamed_transaction || isLogicalApplyWorker) return false; - Assert(stream_fd != -1); Assert(TransactionIdIsValid(stream_xid)); /* @@ -278,11 +408,16 @@ handle_streamed_transaction(const char action, StringInfo s) Assert(TransactionIdIsValid(xid)); - /* Add the new subxact to the array (unless already there). */ - subxact_info_add(xid); + /* + * Find worker for requested xid. + */ + entry = find_or_start_worker(stream_xid, false); - /* write the change to the current file */ - stream_write_change(action, s); + // elog(LOG, "sending message of length=%d and raw=%s, action=%s", s->len, s->data, (char *) &action); + shm_mq_send(entry->mq_handle, s->len, s->data, false); + nchanges += 1; + + // iter_sleep(3600); return true; } @@ -643,7 +778,8 @@ apply_handle_origin(StringInfo s) static void apply_handle_stream_start(StringInfo s) { - bool first_segment; + bool first_segment; + WorkerState *entry; Assert(!in_streamed_transaction); @@ -652,17 +788,16 @@ apply_handle_stream_start(StringInfo s) /* extract XID of the top-level transaction */ stream_xid = logicalrep_read_stream_start(s, &first_segment); + nchanges = 0; - /* open the spool file for this transaction */ - stream_open_file(MyLogicalRepWorker->subid, stream_xid, first_segment); + /* Find worker for requested xid */ + entry = find_or_start_worker(stream_xid, true); - /* - * if this is not the first segment, open existing file - * - * XXX Note that the cleanup is performed by stream_open_file. - */ - if (!first_segment) - subxact_info_read(MyLogicalRepWorker->subid, stream_xid); + SpinLockAcquire(&entry->pstate->mutex); + entry->pstate->ready = false; + SpinLockRelease(&entry->pstate->mutex); + + elog(LOG, "starting streaming of xid %u", stream_xid); pgstat_report_activity(STATE_RUNNING, NULL); } @@ -673,16 +808,19 @@ apply_handle_stream_start(StringInfo s) static void apply_handle_stream_stop(StringInfo s) { + WorkerState *entry; + char action = 'E'; + Assert(in_streamed_transaction); - /* - * Close the file with serialized changes, and serialize information about - * subxacts for the toplevel transaction. - */ - subxact_info_write(MyLogicalRepWorker->subid, stream_xid); - stream_close_file(); + /* Find worker for requested xid */ + entry = find_or_start_worker(stream_xid, false); + + shm_mq_send(entry->mq_handle, 1, &action, false); + wait_for_worker(entry); in_streamed_transaction = false; + elog(LOG, "stopped streaming of xid %u, %u changes streamed", stream_xid, nchanges); pgstat_report_activity(STATE_IDLE, NULL); } @@ -695,96 +833,67 @@ apply_handle_stream_abort(StringInfo s) { TransactionId xid; TransactionId subxid; + WorkerState *entry; Assert(!in_streamed_transaction); - logicalrep_read_stream_abort(s, &xid, &subxid); - - /* - * If the two XIDs are the same, it's in fact abort of toplevel xact, so - * just delete the files with serialized info. - */ - if (xid == subxid) + if(isLogicalApplyWorker) { - char path[MAXPGPATH]; + subxid = pq_getmsgint(s, 4); - /* - * XXX Maybe this should be an error instead? Can we receive abort for - * a toplevel transaction we haven't received? - */ + ereport(LOG, + (errcode_for_file_access(), + errmsg("[Apply BGW #%u] aborting current transaction xid=%u, subxid=%u", + MyParallelState->n, GetCurrentTransactionIdIfAny(), GetCurrentSubTransactionId()))); - changes_filename(path, MyLogicalRepWorker->subid, xid); + if (subxid == stream_xid) + AbortCurrentTransaction(); + else + { + char *spname = (char *) palloc(64 * sizeof(char)); + sprintf(spname, "savepoint_for_xid_%u", subxid); - if (unlink(path) < 0) - ereport(ERROR, + ereport(LOG, (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", path))); + errmsg("[Apply BGW #%u] rolling back to savepoint %s", MyParallelState->n, spname))); - subxact_filename(path, MyLogicalRepWorker->subid, xid); - - if (unlink(path) < 0) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", path))); + RollbackToSavepoint(spname); + CommitTransactionCommand(); + // RollbackAndReleaseCurrentSubTransaction(); - return; + pfree(spname); + } } else { - /* - * OK, so it's a subxact. We need to read the subxact file for the - * toplevel transaction, determine the offset tracked for the subxact, - * and truncate the file with changes. We also remove the subxacts - * with higher offsets (or rather higher XIDs). - * - * We intentionally scan the array from the tail, because we're likely - * aborting a change for the most recent subtransactions. - * - * XXX Can we rely on the subxact XIDs arriving in sorted order? That - * would allow us to use binary search here. - * - * XXX Or perhaps we can rely on the aborts to arrive in the reverse - * order, i.e. from the inner-most subxact (when nested)? In which - * case we could simply check the last element. - */ + xid = pq_getmsgint(s, 4); + subxid = pq_getmsgint(s, 4); - int64 i; - int64 subidx; - bool found = false; - char path[MAXPGPATH]; + /* Find worker for requested xid */ + entry = find_or_start_worker(stream_xid, false); - subidx = -1; - subxact_info_read(MyLogicalRepWorker->subid, xid); + elog(LOG, "processing abort request of streamed transaction xid %u, subxid %u", + xid, subxid); + shm_mq_send(entry->mq_handle, s->len, s->data, false); - /* FIXME optimize the search by bsearch on sorted data */ - for (i = nsubxacts; i > 0; i--) + if (subxid == stream_xid) { - if (subxacts[i - 1].xid == subxid) - { - subidx = (i - 1); - found = true; - break; - } - } - - /* We should not receive aborts for unknown subtransactions. */ - Assert(found); + char action = 'F'; + shm_mq_send(entry->mq_handle, 1, &action, false); + // shm_mq_send(entry->mq_handle, 0, NULL, false); - /* OK, truncate the file at the right offset. */ - Assert((subidx >= 0) && (subidx < nsubxacts)); + wait_for_worker_to_finish(entry); - changes_filename(path, MyLogicalRepWorker->subid, xid); + elog(LOG, "adding finished apply worker #%u for xid %u to the idle list", + entry->pstate->n, entry->xid); + ApplyWorkersIdleList[nfreeworkers++] = entry; - if (truncate(path, subxacts[subidx].offset)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not truncate file \"%s\": %m", path))); + // elog(LOG, "detaching DSM of apply worker for xid=%u\n", entry->xid); + // dsm_detach(entry->dsm_seg); - /* discard the subxacts added later */ - nsubxacts = subidx; - - /* write the updated subxact list */ - subxact_info_write(MyLogicalRepWorker->subid, xid); + // /* Delete worker entry */ + // (void) hash_search(ApplyWorkersHash, &xid, HASH_REMOVE, NULL); + } } } @@ -794,159 +903,56 @@ apply_handle_stream_abort(StringInfo s) static void apply_handle_stream_commit(StringInfo s) { - int fd; TransactionId xid; - StringInfoData s2; - int nchanges; - - char path[MAXPGPATH]; - char *buffer = NULL; + WorkerState *entry; LogicalRepCommitData commit_data; - MemoryContext oldcxt; - - Assert(!in_streamed_transaction); - - xid = logicalrep_read_stream_commit(s, &commit_data); - - elog(DEBUG1, "received commit for streamed transaction %u", xid); - - /* open the spool file for the committed transaction */ - changes_filename(path, MyLogicalRepWorker->subid, xid); - - elog(DEBUG1, "replaying changes from file '%s'", path); - - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); - if (fd < 0) + if (isLogicalApplyWorker) { - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open file \"%s\": %m", - path))); - } - - /* XXX Should this be allocated in another memory context? */ + // logicalrep_read_stream_commit(s, &commit_data); - oldcxt = MemoryContextSwitchTo(TopMemoryContext); - - buffer = palloc(8192); - initStringInfo(&s2); - - MemoryContextSwitchTo(oldcxt); - - ensure_transaction(); - - /* - * Make sure the handle apply_dispatch methods are aware we're in a remote - * transaction. - */ - in_remote_transaction = true; - pgstat_report_activity(STATE_RUNNING, NULL); - - /* - * Read the entries one by one and pass them through the same logic as in - * apply_dispatch. - */ - nchanges = 0; - while (true) + CommitTransactionCommand(); + } + else { - int nbytes; - int len; - - /* read length of the on-disk record */ - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_CHANGES_READ); - nbytes = read(fd, &len, sizeof(len)); - pgstat_report_wait_end(); - - /* have we reached end of the file? */ - if (nbytes == 0) - break; - - /* do we have a correct length? */ - if (nbytes != sizeof(len)) - { - int save_errno = errno; - - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file: %m"))); - return; - } - - Assert(len > 0); + char action = 'F'; - /* make sure we have sufficiently large buffer */ - buffer = repalloc(buffer, len); - - /* and finally read the data into the buffer */ - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_CHANGES_READ); - if (read(fd, buffer, len) != len) - { - int save_errno = errno; - - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file: %m"))); - return; - } - pgstat_report_wait_end(); + Assert(!in_streamed_transaction); - /* copy the buffer to the stringinfo and call apply_dispatch */ - resetStringInfo(&s2); - appendBinaryStringInfo(&s2, buffer, len); + xid = pq_getmsgint(s, 4); + logicalrep_read_stream_commit(s, &commit_data); - /* Ensure we are reading the data into our memory context. */ - oldcxt = MemoryContextSwitchTo(ApplyMessageContext); + elog(DEBUG1, "received commit for streamed transaction %u", xid); - apply_dispatch(&s2); + /* Find worker for requested xid */ + entry = find_or_start_worker(xid, false); - MemoryContextReset(ApplyMessageContext); + /* Send commit message */ + shm_mq_send(entry->mq_handle, s->len, s->data, false); - MemoryContextSwitchTo(oldcxt); + /* Notify worker, that we are done with this xact */ + shm_mq_send(entry->mq_handle, 1, &action, false); - nchanges++; + wait_for_worker_to_finish(entry); - if (nchanges % 1000 == 0) - elog(DEBUG1, "replayed %d changes from file '%s'", - nchanges, path); + elog(LOG, "adding finished apply worker #%u for xid %u to the idle list", + entry->pstate->n, entry->xid); + ApplyWorkersIdleList[nfreeworkers++] = entry; /* - * send feedback to upstream - * - * XXX Probably should send a valid LSN. But which one? + * Update origin state so we can restart streaming from correct + * position in case of crash. */ - send_feedback(InvalidXLogRecPtr, false, false); - } - - CloseTransientFile(fd); - - /* - * Update origin state so we can restart streaming from correct - * position in case of crash. - */ - replorigin_session_origin_lsn = commit_data.end_lsn; - replorigin_session_origin_timestamp = commit_data.committime; - - CommitTransactionCommand(); - pgstat_report_stat(false); - - store_flush_position(commit_data.end_lsn); - - elog(DEBUG1, "replayed %d (all) changes from file '%s'", - nchanges, path); + replorigin_session_origin_lsn = commit_data.end_lsn; + replorigin_session_origin_timestamp = commit_data.committime; - in_remote_transaction = false; - pgstat_report_activity(STATE_IDLE, NULL); + pgstat_report_stat(false); - /* unlink the files with serialized changes and subxact info */ - stream_cleanup_files(MyLogicalRepWorker->subid, xid); + store_flush_position(commit_data.end_lsn); - pfree(buffer); - pfree(s2.data); + in_remote_transaction = false; + pgstat_report_activity(STATE_IDLE, NULL); + } } /* @@ -965,6 +971,8 @@ apply_handle_relation(StringInfo s) if (handle_streamed_transaction('R', s)) return; + // iter_sleep(3600); + rel = logicalrep_read_rel(s); logicalrep_relmap_update(rel); } @@ -1407,6 +1415,38 @@ apply_dispatch(StringInfo s) { char action = pq_getmsgbyte(s); + if (isLogicalApplyWorker) + { + /* + * Inside logical apply worker we can figure out that new subtransaction + * was started if new change arrived with different xid. In that case we + * can define named savepoint, so that we were able to commit/rollback it + * separately later. + * + * Special case is if the first change comes from subtransuction, then + * we check that current_xid differs from stream_xid. + */ + current_xid = pq_getmsgint(s, 4); + + if (current_xid != stream_xid + && ((TransactionIdIsValid(prev_xid) && current_xid != prev_xid) + || !TransactionIdIsValid(prev_xid))) + { + char *spname = (char *) palloc(64 * sizeof(char)); + sprintf(spname, "savepoint_for_xid_%u", current_xid); + + elog(LOG, "[Apply BGW #%u] defining savepoint %s", MyParallelState->n, spname); + + DefineSavepoint(spname); + CommitTransactionCommand(); + // BeginInternalSubTransaction(NULL); + } + + prev_xid = current_xid; + } + // else + // elog(LOG, "Logical worker: applying dispatch for action=%s", (char *) &action); + switch (action) { /* BEGIN */ @@ -1435,6 +1475,7 @@ apply_dispatch(StringInfo s) break; /* RELATION */ case 'R': + // elog(LOG, "%s worker: applying dispatch for action=R", isLogicalApplyWorker ? "Apply" : "Logical"); apply_handle_relation(s); break; /* TYPE */ @@ -1565,12 +1606,18 @@ UpdateWorkerStats(XLogRecPtr last_lsn, TimestampTz send_time, bool reply) static void worker_onexit(int code, Datum arg) { - int i; + HASH_SEQ_STATUS status; + WorkerState *entry; - elog(LOG, "cleanup files for %d transactions", nxids); - - for (i = nxids-1; i >= 0; i--) - stream_cleanup_files(MyLogicalRepWorker->subid, xids[i]); + if (ApplyWorkersHash != NULL) + { + hash_seq_init(&status, ApplyWorkersHash); + while ((entry = (WorkerState *) hash_seq_search(&status)) != NULL) + { + stop_worker(entry); + } + hash_seq_term(&status); + } } /* @@ -1593,6 +1640,8 @@ LogicalRepApplyLoop(XLogRecPtr last_received) /* mark as idle, before starting to loop */ pgstat_report_activity(STATE_IDLE, NULL); + ApplyWorkersIdleList = palloc(sizeof(WorkerState *) * pool_size); + for (;;) { pgsocket fd = PGINVALID_SOCKET; @@ -1904,8 +1953,9 @@ maybe_reread_subscription(void) Subscription *newsub; bool started_tx = false; + // TODO Probably we have to handle subscription reread in apply workers too. /* When cache state is valid there is nothing to do here. */ - if (MySubscriptionValid) + if (MySubscriptionValid || isLogicalApplyWorker) return; /* This function might be called inside or outside of transaction. */ @@ -2039,608 +2089,50 @@ subscription_change_cb(Datum arg, int cacheid, uint32 hashvalue) MySubscriptionValid = false; } -/* - * subxact_info_write - * Store information about subxacts for a toplevel transaction. - * - * For each subxact we store offset of it's first change in the main file. - * The file is always over-written as a whole, and we also include CRC32C - * checksum of the information. - * - * XXX We should only store subxacts that were not aborted yet. - * - * XXX Maybe we should only include the checksum when the cluster is - * initialized with checksums? - * - * XXX Add calls to pgstat_report_wait_start/pgstat_report_wait_end. - */ +/* SIGHUP: set flag to reload configuration at next convenient time */ static void -subxact_info_write(Oid subid, TransactionId xid) +logicalrep_worker_sighup(SIGNAL_ARGS) { - int fd; - char path[MAXPGPATH]; - uint32 checksum; - Size len; - - Assert(TransactionIdIsValid(xid)); - - subxact_filename(path, subid, xid); - - fd = OpenTransientFile(path, O_CREAT | O_TRUNC | O_WRONLY | PG_BINARY); - if (fd < 0) - { - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not create file \"%s\": %m", - path))); - return; - } - - len = sizeof(SubXactInfo) * nsubxacts; - - /* compute the checksum */ - INIT_CRC32C(checksum); - COMP_CRC32C(checksum, (char *) &nsubxacts, sizeof(nsubxacts)); - COMP_CRC32C(checksum, (char *) subxacts, len); - FIN_CRC32C(checksum); - - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_SUBXACT_WRITE); - - if (write(fd, &checksum, sizeof(checksum)) != sizeof(checksum)) - { - int save_errno = errno; + int save_errno = errno; - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to file \"%s\": %m", - path))); - return; - } + got_SIGHUP = true; - if (write(fd, &nsubxacts, sizeof(nsubxacts)) != sizeof(nsubxacts)) - { - int save_errno = errno; + /* Waken anything waiting on the process latch */ + SetLatch(MyLatch); - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to file \"%s\": %m", - path))); - return; - } + errno = save_errno; +} - if ((len > 0) && (write(fd, subxacts, len) != len)) - { - int save_errno = errno; +/* Logical Replication Apply worker entry point */ +void +ApplyWorkerMain(Datum main_arg) +{ + int worker_slot = DatumGetInt32(main_arg); + MemoryContext oldctx; + char originname[NAMEDATALEN]; + XLogRecPtr origin_startpos; + char *myslotname; + WalRcvStreamOptions options; - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to file \"%s\": %m", - path))); - return; - } + /* Attach to slot */ + logicalrep_worker_attach(worker_slot); - pgstat_report_wait_end(); + /* Setup signal handling */ + pqsignal(SIGHUP, logicalrep_worker_sighup); + pqsignal(SIGTERM, die); + BackgroundWorkerUnblockSignals(); /* - * We don't need to fsync or anything, as we'll recreate the files after a - * crash from scratch. So just close the file. + * We don't currently need any ResourceOwner in a walreceiver process, but + * if we did, we could call CreateAuxProcessResourceOwner here. */ - CloseTransientFile(fd); - /* - * But we free the memory allocated for subxact info. There might be one - * exceptional transaction with many subxacts, and we don't want to keep - * the memory allocated forewer. - * - */ - if (subxacts) - pfree(subxacts); + /* Initialise stats to a sanish value */ + MyLogicalRepWorker->last_send_time = MyLogicalRepWorker->last_recv_time = + MyLogicalRepWorker->reply_time = GetCurrentTimestamp(); - subxacts = NULL; - subxact_last = InvalidTransactionId; - nsubxacts = 0; - nsubxacts_max = 0; -} - -/* - * subxact_info_read - * Restore information about subxacts of a streamed transaction. - * - * Read information about subxacts into the global variables, and while - * reading the information verify the checksum. - * - * XXX Add calls to pgstat_report_wait_start/pgstat_report_wait_end. - * - * XXX Do we need to allocate it in TopMemoryContext? - */ -static void -subxact_info_read(Oid subid, TransactionId xid) -{ - int fd; - char path[MAXPGPATH]; - uint32 checksum; - uint32 checksum_new; - Size len; - MemoryContext oldctx; - - Assert(TransactionIdIsValid(xid)); - Assert(!subxacts); - Assert(nsubxacts == 0); - Assert(nsubxacts_max == 0); - - subxact_filename(path, subid, xid); - - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); - if (fd < 0) - { - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open file \"%s\": %m", - path))); - return; - } - - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_SUBXACT_READ); - - /* read the checksum */ - if (read(fd, &checksum, sizeof(checksum)) != sizeof(checksum)) - { - int save_errno = errno; - - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file \"%s\": %m", - path))); - return; - } - - /* read number of subxact items */ - if (read(fd, &nsubxacts, sizeof(nsubxacts)) != sizeof(nsubxacts)) - { - int save_errno = errno; - - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file \"%s\": %m", - path))); - return; - } - - pgstat_report_wait_end(); - - len = sizeof(SubXactInfo) * nsubxacts; - - /* we keep the maximum as a power of 2 */ - nsubxacts_max = 1 << my_log2(nsubxacts); - - /* subxacts are long-lived */ - oldctx = MemoryContextSwitchTo(TopMemoryContext); - subxacts = palloc(nsubxacts_max * sizeof(SubXactInfo)); - MemoryContextSwitchTo(oldctx); - - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_SUBXACT_READ); - - if ((len > 0) && ((read(fd, subxacts, len)) != len)) - { - int save_errno = errno; - - CloseTransientFile(fd); - errno = save_errno; - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file \"%s\": %m", - path))); - return; - } - - pgstat_report_wait_end(); - - /* recompute the checksum */ - INIT_CRC32C(checksum_new); - COMP_CRC32C(checksum_new, (char *) &nsubxacts, sizeof(nsubxacts)); - COMP_CRC32C(checksum_new, (char *) subxacts, len); - FIN_CRC32C(checksum_new); - - if (checksum_new != checksum) - ereport(ERROR, - (errmsg("checksum failure when reading subxacts"))); - - CloseTransientFile(fd); -} - -/* - * subxact_info_add - * Add information about a subxact (offset in the main file). - * - * XXX Do we need to allocate it in TopMemoryContext? - */ -static void -subxact_info_add(TransactionId xid) -{ - int64 i; - - /* - * If the XID matches the toplevel transaction, we don't want to add it. - */ - if (stream_xid == xid) - return; - - /* - * In most cases we're checking the same subxact as we've already seen in - * the last call, so make ure just ignore it (this change comes later). - */ - if (subxact_last == xid) - return; - - /* OK, remember we're processing this XID. */ - subxact_last = xid; - - /* - * Check if the transaction is already present in the array of subxact. We - * intentionally scan the array from the tail, because we're likely adding - * a change for the most recent subtransactions. - * - * XXX Can we rely on the subxact XIDs arriving in sorted order? That - * would allow us to use binary search here. - */ - for (i = nsubxacts; i > 0; i--) - { - /* found, so we're done */ - if (subxacts[i - 1].xid == xid) - return; - } - - /* This is a new subxact, so we need to add it to the array. */ - - if (nsubxacts == 0) - { - MemoryContext oldctx; - - nsubxacts_max = 128; - oldctx = MemoryContextSwitchTo(TopMemoryContext); - subxacts = palloc(nsubxacts_max * sizeof(SubXactInfo)); - MemoryContextSwitchTo(oldctx); - } - else if (nsubxacts == nsubxacts_max) - { - nsubxacts_max *= 2; - subxacts = repalloc(subxacts, nsubxacts_max * sizeof(SubXactInfo)); - } - - subxacts[nsubxacts].xid = xid; - subxacts[nsubxacts].offset = lseek(stream_fd, 0, SEEK_END); - - nsubxacts++; -} - -/* format filename for file containing the info about subxacts */ -static void -subxact_filename(char *path, Oid subid, TransactionId xid) -{ - char tempdirpath[MAXPGPATH]; - - TempTablespacePath(tempdirpath, DEFAULTTABLESPACE_OID); - - /* - * We might need to create the tablespace's tempfile directory, if no - * one has yet done so. - * - * Don't check for error from mkdir; it could fail if the directory - * already exists (maybe someone else just did the same thing). If - * it doesn't work then we'll bomb out when opening the file - */ - mkdir(tempdirpath, S_IRWXU); - - snprintf(path, MAXPGPATH, "%s/logical-%u-%u.subxacts", - tempdirpath, subid, xid); -} - -/* format filename for file containing serialized changes */ -static void -changes_filename(char *path, Oid subid, TransactionId xid) -{ - char tempdirpath[MAXPGPATH]; - - TempTablespacePath(tempdirpath, DEFAULTTABLESPACE_OID); - - /* - * We might need to create the tablespace's tempfile directory, if no - * one has yet done so. - * - * Don't check for error from mkdir; it could fail if the directory - * already exists (maybe someone else just did the same thing). If - * it doesn't work then we'll bomb out when opening the file - */ - mkdir(tempdirpath, S_IRWXU); - - snprintf(path, MAXPGPATH, "%s/logical-%u-%u.changes", - tempdirpath, subid, xid); -} - -/* - * stream_cleanup_files - * Cleanup files for a subscription / toplevel transaction. - * - * Remove files with serialized changes and subxact info for a particular - * toplevel transaction. Each subscription has a separate set of files. - * - * Note: The files may not exists, so handle ENOENT as non-error. - * - * TODO: Add missing_ok flag to specify in which cases it's OK not to - * find the files, and when it's an error. - */ -static void -stream_cleanup_files(Oid subid, TransactionId xid) -{ - int i; - char path[MAXPGPATH]; - bool found = false; - - subxact_filename(path, subid, xid); - - if ((unlink(path) < 0) && (errno != ENOENT)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", path))); - - changes_filename(path, subid, xid); - - if ((unlink(path) < 0) && (errno != ENOENT)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", path))); - - /* - * Cleanup the XID from the array - find the XID in the array and - * remove it by shifting all the remaining elements. The array is - * bound to be fairly small (maximum number of in-progress xacts, - * so max_connections + max_prepared_transactions) so simply loop - * through the array and find index of the XID. Then move the rest - * of the array by one element to the left. - * - * Notice we also call this from stream_open_file for first segment - * of each transaction, to deal with possible left-overs after a - * crash, so it's entirely possible not to find the XID in the - * array here. In that case we don't remove anything. - * - * XXX Perhaps it'd be better to handle this automatically after a - * restart, instead of doing it over and over for each transaction. - */ - for (i = 0; i < nxids; i++) - { - if (xids[i] == xid) - { - found = true; - break; - } - } - - if (!found) - return; - - /* - * Move the last entry from the array to the place. We don't keep - * the streamed transactions sorted or anything - we only expect - * a few of them in progress (max_connections + max_prepared_xacts) - * so linear search is just fine. - */ - xids[i] = xids[nxids-1]; - nxids--; -} - -/* - * stream_open_file - * Open file we'll use to serialize changes for a toplevel transaction. - * - * Open a file for streamed changes from a toplevel transaction identified - * by stream_xid (global variable). If it's the first chunk of streamed - * changes for this transaction, perform cleanup by removing existing - * files after a possible previous crash. - * - * This can only be called at the beginning of a "streaming" block, i.e. - * between stream_start/stream_stop messages from the upstream. - */ -static void -stream_open_file(Oid subid, TransactionId xid, bool first_segment) -{ - char path[MAXPGPATH]; - int flags; - - Assert(in_streamed_transaction); - Assert(OidIsValid(subid)); - Assert(TransactionIdIsValid(xid)); - Assert(stream_fd == -1); - - /* - * If this is the first segment for this transaction, try removing - * existing files (if there are any, possibly after a crash). - */ - if (first_segment) - { - MemoryContext oldcxt; - - /* XXX make sure there are no previous files for this transaction */ - stream_cleanup_files(subid, xid); - - oldcxt = MemoryContextSwitchTo(TopMemoryContext); - - /* - * We need to remember the XIDs we spilled to files, so that we can - * remove them at worker exit (e.g. after DROP SUBSCRIPTION). - * - * The number of XIDs we may need to track is fairly small, because - * we can only stream toplevel xacts (so limited by max_connections - * and max_prepared_transactions), and we only stream the large ones. - * So we simply keep the XIDs in an unsorted array. If the number of - * xacts gets large for some reason (e.g. very high max_connections), - * a more elaborate approach might be better - e.g. sorted array, to - * speed-up the lookups. - */ - if (nxids == maxnxids) /* array of XIDs is full */ - { - if (!xids) - { - maxnxids = 64; - xids = palloc(maxnxids * sizeof(TransactionId)); - } - else - { - maxnxids = 2 * maxnxids; - xids = repalloc(xids, maxnxids * sizeof(TransactionId)); - } - } - - xids[nxids++] = xid; - - MemoryContextSwitchTo(oldcxt); - } - - changes_filename(path, subid, xid); - - elog(DEBUG1, "opening file '%s' for streamed changes", path); - - /* - * If this is the first streamed segment, the file must not exist, so - * make sure we're the ones creating it. Otherwise just open the file - * for writing, in append mode. - */ - if (first_segment) - flags = (O_WRONLY | O_CREAT | O_EXCL | PG_BINARY); - else - flags = (O_WRONLY | O_APPEND | PG_BINARY); - - stream_fd = OpenTransientFile(path, flags); - - if (stream_fd < 0) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open file \"%s\": %m", - path))); -} - -/* - * stream_close_file - * Close the currently open file with streamed changes. - * - * This can only be called at the beginning of a "streaming" block, i.e. - * between stream_start/stream_stop messages from the upstream. - */ -static void -stream_close_file(void) -{ - Assert(in_streamed_transaction); - Assert(TransactionIdIsValid(stream_xid)); - Assert(stream_fd != -1); - - CloseTransientFile(stream_fd); - - stream_xid = InvalidTransactionId; - stream_fd = -1; -} - -/* - * stream_write_change - * Serialize a change to a file for the current toplevel transaction. - * - * The change is serialied in a simple format, with length (not including - * the length), action code (identifying the message type) and message - * contents (without the subxact TransactionId value). - * - * XXX The subxact file includes CRC32C of the contents. Maybe we should - * include something like that here too, but doing so will not be as - * straighforward, because we write the file in chunks. - */ -static void -stream_write_change(char action, StringInfo s) -{ - int len; - - Assert(in_streamed_transaction); - Assert(TransactionIdIsValid(stream_xid)); - Assert(stream_fd != -1); - - /* total on-disk size, including the action type character */ - len = (s->len - s->cursor) + sizeof(char); - - pgstat_report_wait_start(WAIT_EVENT_LOGICAL_CHANGES_WRITE); - - /* first write the size */ - if (write(stream_fd, &len, sizeof(len)) != sizeof(len)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not serialize streamed change to file: %m"))); - - /* then the action */ - if (write(stream_fd, &action, sizeof(action)) != sizeof(action)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not serialize streamed change to file: %m"))); - - /* and finally the remaining part of the buffer (after the XID) */ - len = (s->len - s->cursor); - - if (write(stream_fd, &s->data[s->cursor], len) != len) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not serialize streamed change to file: %m"))); - - pgstat_report_wait_end(); -} - -/* SIGHUP: set flag to reload configuration at next convenient time */ -static void -logicalrep_worker_sighup(SIGNAL_ARGS) -{ - int save_errno = errno; - - got_SIGHUP = true; - - /* Waken anything waiting on the process latch */ - SetLatch(MyLatch); - - errno = save_errno; -} - -/* Logical Replication Apply worker entry point */ -void -ApplyWorkerMain(Datum main_arg) -{ - int worker_slot = DatumGetInt32(main_arg); - MemoryContext oldctx; - char originname[NAMEDATALEN]; - XLogRecPtr origin_startpos; - char *myslotname; - WalRcvStreamOptions options; - - /* Attach to slot */ - logicalrep_worker_attach(worker_slot); - - /* Setup signal handling */ - pqsignal(SIGHUP, logicalrep_worker_sighup); - pqsignal(SIGTERM, die); - BackgroundWorkerUnblockSignals(); - - /* - * We don't currently need any ResourceOwner in a walreceiver process, but - * if we did, we could call CreateAuxProcessResourceOwner here. - */ - - /* Initialise stats to a sanish value */ - MyLogicalRepWorker->last_send_time = MyLogicalRepWorker->last_recv_time = - MyLogicalRepWorker->reply_time = GetCurrentTimestamp(); - - /* Load the libpq-specific functions */ - load_file("libpqwalreceiver", false); + /* Load the libpq-specific functions */ + load_file("libpqwalreceiver", false); /* Run as replica session replication role. */ SetConfigOption("session_replication_role", "replica", @@ -2798,3 +2290,580 @@ IsLogicalWorker(void) { return MyLogicalRepWorker != NULL; } + +/* + * Apply Background Worker main loop. + */ +void +LogicalApplyBgwMain(Datum main_arg) +{ + volatile ParallelState *pst; + + dsm_segment *seg; + shm_toc *toc; + PGPROC *registrant; + shm_mq *mq; + shm_mq_handle *mqh; + shm_mq_result shmq_res; + // ConditionVariable cv; + LogicalRepWorker lrw; + MemoryContext oldcontext; + + MemoryContextSwitchTo(TopMemoryContext); + + /* Load the subscription into persistent memory context. */ + ApplyContext = AllocSetContextCreate(TopMemoryContext, + "ApplyContext", + ALLOCSET_DEFAULT_SIZES); + + oldcontext = MemoryContextSwitchTo(ApplyContext); + + /* + * Init the ApplyMessageContext which we clean up after each replication + * protocol message. + */ + ApplyMessageContext = AllocSetContextCreate(ApplyContext, + "ApplyMessageContext", + ALLOCSET_DEFAULT_SIZES); + + isLogicalApplyWorker = true; + + /* + * Establish signal handlers. + * + * We want CHECK_FOR_INTERRUPTS() to kill off this worker process just as + * it would a normal user backend. To make that happen, we establish a + * signal handler that is a stripped-down version of die(). + */ + pqsignal(SIGTERM, handle_sigterm); + BackgroundWorkerUnblockSignals(); + + /* + * Connect to the dynamic shared memory segment. + * + * The backend that registered this worker passed us the ID of a shared + * memory segment to which we must attach for further instructions. In + * order to attach to dynamic shared memory, we need a resource owner. + * Once we've mapped the segment in our address space, attach to the table + * of contents so we can locate the various data structures we'll need to + * find within the segment. + */ + CurrentResourceOwner = ResourceOwnerCreate(NULL, "Logical apply worker"); + seg = dsm_attach(DatumGetInt32(main_arg)); + if (seg == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("unable to map dynamic shared memory segment"))); + toc = shm_toc_attach(PG_LOGICAL_APPLY_SHM_MAGIC, dsm_segment_address(seg)); + if (toc == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("bad magic number in dynamic shared memory segment"))); + + /* + * Acquire a worker number. + * + * By convention, the process registering this background worker should + * have stored the control structure at key 0. We look up that key to + * find it. Our worker number gives our identity: there may be just one + * worker involved in this parallel operation, or there may be many. + */ + pst = shm_toc_lookup(toc, 0, false); + MyParallelState = pst; + + SpinLockAcquire(&pst->mutex); + pst->attached = true; + SpinLockRelease(&pst->mutex); + + /* + * Attach to the message queue. + */ + mq = shm_toc_lookup(toc, 1, false); + shm_mq_set_receiver(mq, MyProc); + mqh = shm_mq_attach(mq, seg, NULL); + + /* Restore database connection. */ + BackgroundWorkerInitializeConnectionByOid(pst->database_id, + pst->authenticated_user_id, 0); + + /* + * Set the client encoding to the database encoding, since that is what + * the leader will expect. + */ + SetClientEncoding(GetDatabaseEncoding()); + + lrw.subid = pst->subid; + MyLogicalRepWorker = &lrw; + + stream_xid = pst->stream_xid; + + StartTransactionCommand(); + BeginTransactionBlock(); + CommitTransactionCommand(); + StartTransactionCommand(); + // PushActiveSnapshot(GetTransactionSnapshot()); + + MySubscription = GetSubscription(MyLogicalRepWorker->subid, true); + + /* + * Indicate that we're fully initialized and ready to begin the main part + * of the parallel operation. + * + * Once we signal that we're ready, the user backend is entitled to assume + * that our on_dsm_detach callbacks will fire before we disconnect from + * the shared memory segment and exit. Generally, that means we must have + * attached to all relevant dynamic shared memory data structures by now. + */ + SpinLockAcquire(&pst->mutex); + pst->ready = true; + // cv = pst->cv; + // if (pst->workers_ready == pst->workers_total) + // { + // registrant = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid); + // if (registrant == NULL) + // { + // elog(DEBUG1, "registrant backend has exited prematurely"); + // proc_exit(1); + // } + // SetLatch(®istrant->procLatch); + // } + SpinLockRelease(&pst->mutex); + elog(LOG, "[Apply BGW #%u] started", pst->n); + + registrant = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid); + SetLatch(®istrant->procLatch); + + for (;;) + { + void *data; + Size len; + StringInfoData s; + MemoryContext oldctx; + + CHECK_FOR_INTERRUPTS(); + + /* Ensure we are reading the data into our memory context. */ + oldctx = MemoryContextSwitchTo(ApplyMessageContext); + + shmq_res = shm_mq_receive(mqh, &len, &data, false); + + if (shmq_res != SHM_MQ_SUCCESS) + break; + + if (len == 0) + { + elog(LOG, "[Apply BGW #%u] got zero-length message, stopping", pst->n); + break; + } + else + { + s.cursor = 0; + s.maxlen = -1; + s.data = (char *) data; + s.len = len; + + /* + * We use first byte of message for additional communication between + * main Logical replication worker and Apply BGWorkers, so if it + * differs from 'w', then process it first. + */ + switch (pq_getmsgbyte(&s)) + { + /* Stream stop */ + case 'E': + { + in_remote_transaction = false; + + SpinLockAcquire(&pst->mutex); + pst->ready = true; + SpinLockRelease(&pst->mutex); + SetLatch(®istrant->procLatch); + + elog(LOG, "[Apply BGW #%u] ended processing streaming chunk, waiting on shm_mq_receive", pst->n); + + continue; + } + /* Reassign to the new transaction */ + case 'R': + { + elog(LOG, "[Apply BGW #%u] switching from processing xid %u to xid %u", + pst->n, stream_xid, pst->stream_xid); + stream_xid = pst->stream_xid; + + StartTransactionCommand(); + BeginTransactionBlock(); + CommitTransactionCommand(); + StartTransactionCommand(); + + MySubscription = GetSubscription(MyLogicalRepWorker->subid, true); + + continue; + } + /* Finished processing xact */ + case 'F': + { + elog(LOG, "[Apply BGW #%u] finished processing xact %u", pst->n, stream_xid); + + MemoryContextSwitchTo(ApplyContext); + + CommitTransactionCommand(); + EndTransactionBlock(); + CommitTransactionCommand(); + + SpinLockAcquire(&pst->mutex); + pst->finished = true; + SpinLockRelease(&pst->mutex); + + continue; + } + default: + break; + } + + pq_getmsgint64(&s); // Read LSN info + pq_getmsgint64(&s); // TODO Do we need to process it here again somehow? + pq_getmsgint64(&s); + + /* + * Make sure the handle apply_dispatch methods are aware we're in a remote + * transaction. + */ + in_remote_transaction = true; + pgstat_report_activity(STATE_RUNNING, NULL); + + elog(DEBUG5, "[Apply BGW #%u] applying dispatch for action=%s", + pst->n, (char *) &s.data[s.cursor]); + apply_dispatch(&s); + } + + MemoryContextSwitchTo(oldctx); + MemoryContextReset(ApplyMessageContext); + } + + CommitTransactionCommand(); + EndTransactionBlock(); + CommitTransactionCommand(); + + MemoryContextSwitchTo(oldcontext); + MemoryContextReset(ApplyContext); + + SpinLockAcquire(&pst->mutex); + pst->finished = true; + // if (pst->workers_finished == pst->workers_total) + // { + // registrant = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid); + // if (registrant == NULL) + // { + // elog(DEBUG1, "registrant backend has exited prematurely"); + // proc_exit(1); + // } + // SetLatch(®istrant->procLatch); + // } + SpinLockRelease(&pst->mutex); + + elog(LOG, "[Apply BGW #%u] exiting", pst->n); + + /* Signal main process that we are done. */ + // ConditionVariableBroadcast(&cv); + SetLatch(®istrant->procLatch); + + /* + * We're done. Explicitly detach the shared memory segment so that we + * don't get a resource leak warning at commit time. This will fire any + * on_dsm_detach callbacks we've registered, as well. Once that's done, + * we can go ahead and exit. + */ + dsm_detach(seg); + proc_exit(0); +} + +/* + * When we receive a SIGTERM, we set InterruptPending and ProcDiePending just + * like a normal backend. The next CHECK_FOR_INTERRUPTS() will do the right + * thing. + */ +static void +handle_sigterm(SIGNAL_ARGS) +{ + int save_errno = errno; + + SetLatch(MyLatch); + + if (!proc_exit_inprogress) + { + InterruptPending = true; + ProcDiePending = true; + } + + errno = save_errno; +} + +/* + * Set up a dynamic shared memory segment. + * + * We set up a control region that contains a ParallelState, + * plus one region per message queue. There are as many message queues as + * the number of workers. + */ +static void +setup_dsm(WorkerState *wstate) +{ + shm_toc_estimator e; + int toc_key = 0; + Size segsize; + dsm_segment *seg; + shm_toc *toc; + ParallelState *pst; + shm_mq *mq; + int64 queue_size = 160000000; /* 16 MB for now */ + + /* Ensure a valid queue size. */ + if (queue_size < 0 || ((uint64) queue_size) < shm_mq_minimum_size) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("queue size must be at least %zu bytes", + shm_mq_minimum_size))); + if (queue_size != ((Size) queue_size)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("queue size overflows size_t"))); + + /* + * Estimate how much shared memory we need. + * + * Because the TOC machinery may choose to insert padding of oddly-sized + * requests, we must estimate each chunk separately. + * + * We need one key to register the location of the header, and we need + * nworkers keys to track the locations of the message queues. + */ + shm_toc_initialize_estimator(&e); + shm_toc_estimate_chunk(&e, sizeof(ParallelState)); + shm_toc_estimate_chunk(&e, (Size) queue_size); + + shm_toc_estimate_keys(&e, 1 + 1); + segsize = shm_toc_estimate(&e); + + /* Create the shared memory segment and establish a table of contents. */ + seg = dsm_create(shm_toc_estimate(&e), 0); + toc = shm_toc_create(PG_LOGICAL_APPLY_SHM_MAGIC, dsm_segment_address(seg), + segsize); + + /* Set up the header region. */ + pst = shm_toc_allocate(toc, sizeof(ParallelState)); + SpinLockInit(&pst->mutex); + pst->attached = false; + pst->ready = false; + pst->finished = false; + pst->database_id = MyDatabaseId; + pst->subid = MyLogicalRepWorker->subid; + pst->stream_xid = stream_xid; + pst->authenticated_user_id = GetAuthenticatedUserId(); + pst->n = nworkers + 1; + // ConditionVariableInit(&pst->cv); + + shm_toc_insert(toc, toc_key++, pst); + + /* Set up one message queue per worker, plus one. */ + mq = shm_mq_create(shm_toc_allocate(toc, (Size) queue_size), + (Size) queue_size); + shm_toc_insert(toc, toc_key++, mq); + shm_mq_set_sender(mq, MyProc); + + /* Attach the queues. */ + wstate->mq_handle = shm_mq_attach(mq, seg, wstate->handle); + + /* Return results to caller. */ + wstate->dsm_seg = seg; + wstate->pstate = pst; +} + +/* + * Register background workers. + */ +static void +setup_background_worker(WorkerState *wstate) +{ + MemoryContext oldcontext; + BackgroundWorker worker; + + elog(LOG, "setting up apply worker #%u", nworkers + 1); + + /* + * TOCHECK: We need the worker_state object and the background worker handles to + * which it points to be allocated in TopMemoryContext rather than + * ApplyMessageContext; otherwise, they'll be destroyed before the on_dsm_detach + * hooks run. + */ + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + + setup_dsm(wstate); + + /* + * Arrange to kill all the workers if we abort before all workers are + * finished hooking themselves up to the dynamic shared memory segment. + * + * If we die after all the workers have finished hooking themselves up to + * the dynamic shared memory segment, we'll mark the two queues to which + * we're directly connected as detached, and the worker(s) connected to + * those queues will exit, marking any other queues to which they are + * connected as detached. This will cause any as-yet-unaware workers + * connected to those queues to exit in their turn, and so on, until + * everybody exits. + * + * But suppose the workers which are supposed to connect to the queues to + * which we're directly attached exit due to some error before they + * actually attach the queues. The remaining workers will have no way of + * knowing this. From their perspective, they're still waiting for those + * workers to start, when in fact they've already died. + */ + on_dsm_detach(wstate->dsm_seg, cleanup_background_worker, + PointerGetDatum(wstate)); + + /* Configure a worker. */ + MemSet(&worker, 0, sizeof(BackgroundWorker)); + + worker.bgw_flags = BGWORKER_SHMEM_ACCESS | + BGWORKER_BACKEND_DATABASE_CONNECTION; + worker.bgw_start_time = BgWorkerStart_ConsistentState; + worker.bgw_restart_time = BGW_NEVER_RESTART; + worker.bgw_notify_pid = MyProcPid; + sprintf(worker.bgw_library_name, "postgres"); + sprintf(worker.bgw_function_name, "LogicalApplyBgwMain"); + + worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(wstate->dsm_seg)); + + /* Register the workers. */ + snprintf(worker.bgw_name, BGW_MAXLEN, + "logical replication apply worker #%u for subscription %u", + nworkers + 1, MySubscription->oid); + if (!RegisterDynamicBackgroundWorker(&worker, &wstate->handle)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_RESOURCES), + errmsg("could not register background process"), + errhint("You may need to increase max_worker_processes."))); + + /* All done. */ + MemoryContextSwitchTo(oldcontext); + + /* Wait for worker to become ready. */ + wait_for_worker(wstate); + + /* + * Once we reach this point, all workers are ready. We no longer need to + * kill them if we die; they'll die on their own as the message queues + * shut down. + */ + cancel_on_dsm_detach(wstate->dsm_seg, cleanup_background_worker, + PointerGetDatum(wstate)); + + nworkers += 1; +} + +static void +cleanup_background_worker(dsm_segment *seg, Datum arg) +{ + WorkerState *wstate = (WorkerState *) DatumGetPointer(arg); + + TerminateBackgroundWorker(wstate->handle); +} + +static void +wait_for_worker(WorkerState *wstate) +{ + bool result = false; + + for (;;) + { + // ConditionVariable cv; + bool ready; + + /* If the worker is ready, we have succeeded. */ + SpinLockAcquire(&wstate->pstate->mutex); + ready = wstate->pstate->ready; + // cv = wstate->pstate->cv; + SpinLockRelease(&wstate->pstate->mutex); + if (ready) + { + result = true; + break; + } + + /* If any workers (or the postmaster) have died, we have failed. */ + if (!check_worker_status(wstate)) + { + result = false; + break; + } + + /* Wait for the workers to wake us up. */ + // ConditionVariableSleep(&cv, WAIT_EVENT_LOGICAL_APPLY_WORKER_READY); + + /* Wait to be signalled. */ + WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, + WAIT_EVENT_LOGICAL_APPLY_WORKER_READY); + + /* Reset the latch so we don't spin. */ + ResetLatch(MyLatch); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); + } + + // ConditionVariableCancelSleep(); + + if (!result) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_RESOURCES), + errmsg("one or more background workers failed to start"))); +} + +static bool +check_worker_status(WorkerState *wstate) +{ + BgwHandleStatus status; + pid_t pid; + + status = GetBackgroundWorkerPid(wstate->handle, &pid); + if (status == BGWH_STOPPED || status == BGWH_POSTMASTER_DIED) + return false; + + /* Otherwise, things still look OK. */ + return true; +} + +static void +wait_for_worker_to_finish(WorkerState *wstate) +{ + elog(LOG, "waiting for apply worker #%u to finish processing xid %u", + wstate->pstate->n, wstate->xid); + + for (;;) + { + // ConditionVariable cv; + bool finished; + + /* If the worker is finished, we have succeeded. */ + SpinLockAcquire(&wstate->pstate->mutex); + finished = wstate->pstate->finished; + // cv = wstate->pstate->cv; + SpinLockRelease(&wstate->pstate->mutex); + if (finished) + { + break; + } + + /* Wait for the workers to wake us up. */ + // ConditionVariableSleep(&cv, WAIT_EVENT_LOGICAL_APPLY_WORKER_READY); + + /* Wait to be signalled. */ + WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, + WAIT_EVENT_LOGICAL_APPLY_WORKER_READY); + + /* Reset the latch so we don't spin. */ + ResetLatch(MyLatch); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); + } +} diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 3a89e23488..7c72db9e83 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -819,6 +819,7 @@ typedef enum WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATING, WAIT_EVENT_HASH_GROW_BUCKETS_ELECTING, WAIT_EVENT_HASH_GROW_BUCKETS_REINSERTING, + WAIT_EVENT_LOGICAL_APPLY_WORKER_READY, WAIT_EVENT_LOGICAL_SYNC_DATA, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE, WAIT_EVENT_MQ_INTERNAL, diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h index 802275311d..afb15c2736 100644 --- a/src/include/replication/logicalproto.h +++ b/src/include/replication/logicalproto.h @@ -122,12 +122,10 @@ extern TransactionId logicalrep_read_stream_stop(StringInfo in); extern void logicalrep_write_stream_commit(StringInfo out, ReorderBufferTXN *txn, XLogRecPtr commit_lsn); -extern TransactionId logicalrep_read_stream_commit(StringInfo out, +extern void logicalrep_read_stream_commit(StringInfo out, LogicalRepCommitData *commit_data); extern void logicalrep_write_stream_abort(StringInfo out, TransactionId xid, TransactionId subxid); -extern void logicalrep_read_stream_abort(StringInfo in, - TransactionId *xid, TransactionId *subxid); #endif /* LOGICALREP_PROTO_H */ diff --git a/src/include/replication/logicalworker.h b/src/include/replication/logicalworker.h index e9524aefd9..30ad40247d 100644 --- a/src/include/replication/logicalworker.h +++ b/src/include/replication/logicalworker.h @@ -13,6 +13,7 @@ #define LOGICALWORKER_H extern void ApplyWorkerMain(Datum main_arg); +extern void LogicalApplyBgwMain(Datum main_arg); extern bool IsLogicalWorker(void); -- 2.17.1 --------------524DAFED047A6CA78CDF53FC--