1. Dec 27, 2023
    • Dimitri Fontaine's avatar
      Use our SQLite catalogs for the pgcopydb sentinel table. · cb63d711
      Dimitri Fontaine authored
      The main use-case for the sentinel table is to communicate progress made by
      the three independent worker processes for stream, transform, and replay.
      It is also needed to communicate new startpos, endpos and apply values with
      those processes from another pgcopydb (interactive) command, a process
      that's not in the process tree.
      
      This was previously solved by creating and using a pgcopydb.sentinel table
      on the source database. Now that we have a SQLite database internal to the
      pgcopydb run, we can use that instead.
      cb63d711
    • Dimitri Fontaine's avatar
    • Arunprasad Rajkumar's avatar
    • Dimitri Fontaine's avatar
      Remove summary files, use our SQLite database instead. (#590) · 75e1e8d7
      Dimitri Fontaine authored
      * Remove summary files, use our SQLite database instead.
      
      * Get rid of summary files for the indexing and constraints too.
      
      This allows also to entirely remove the need for semaphores to handle
      concurrency between worker processes, using SQLite insert-or-ignore for
      concurrency control instead.
      
      Also the idea of TablePaths and IndexPaths elements are gone, with the lock
      files and the done files mechanisms.
      
      * Protect SQLite concurrent write access with a semaphore.
      
      SQLite has not been designed for write-write concurrency, so implement a
      critical section in our code so that SQLite only sees a single writer at all
      times. It may still see multiple readers though.
      
      Because we have re-entrant queries (an SQLite iterator function may then
      choose to run another SQLite query), this commit also adds support for
      re-entrant semaphore in a way that doesn't call into semop(2) again when we
      already are in the critical section.
      
      * Assorted fixes.
      75e1e8d7
    • Dimitri Fontaine's avatar
    • Dimitri Fontaine's avatar
      Fix error handling (--fail-fast) for copy workers. (#598) · 4ce24428
      Dimitri Fontaine authored
      When the COPY table-data workers fail before the iteration over the list of
      tables is done, we have a race condition where the COPY supervisor would be
      busy and is not using waitpid(), thus not reacting to worker process
      termination.
      
      To solve, limit the responsibilities of the COPY supervisor process even
      more and create a new process that's responsible for iterating over the
      table list and sending tables/parts to the queue, etc.
      4ce24428
    • Dimitri Fontaine's avatar
      Review the COPY arguments API to fix TRUNCATE calls. (#597) · 9db10402
      Dimitri Fontaine authored
      The code to call TRUNCATE ONLY was only active for tables setup with COPY
      partitioning (--split-tables-larger-than), and was forced to "false" for the
      other tables.
      
      The code also evolved in a way that it would build a sub-SELECT query with
      the table attribute list as the "srcQname" argument to the pgsql.c internal
      bits for the copy, making it impossible to then re-use that bit in the sql
      command for the TRUNCATE operation.
      
      To fix, implement a new way to prepare the COPY query bits and pieces so
      that we can re-use the qualified table name in the TRUNCATE command and also
      build a full COPY (SELECT a, b, c FROM ONLY t WHERE ...) TO STDOUT; query.
      
      In passing, because of the way we are changing the summary files to use our
      internal SQLite database instead, also push the TRUNCATE command of COPY
      partitionned table to the COPY supervisor process. This is a better way to
      solve the concurrency issues and make sure that TRUNCATE is done only once,
      and also finished before any of the copy-data worker processes get started.
      9db10402
  2. Dec 22, 2023
    • Shubham Dhama's avatar
      Fix escaping of identifiers while transforming for wal2json plugin. (#595) · 30a87a7f
      Shubham Dhama authored
      
      
      * add quotes identifiers
      
      * test changes
      
      * Fix escaping of identifiers while transforming for wal2json plugin.
      
      wal2json doesn't escape identifiers as test_decoding do. To fix this issue
      we are using PQescapeIdentifier function. Even though this function doesn't
      require PGconn to be connected, but creating an empty PGconn object was
      unfeasible. Some fields of PGconn that are required by new versions of
      libpq for PQescapeIdentifier are not available in older PGconn. So decided
      to do this the right way, but creating PGconn with an actual server
      connection. It turned out more simpler than managing a dummy PGconn object.
      
      * Fix review comments.
      
      * Fix style.
      
      ---------
      
      Co-authored-by: default avatarVaibhaveS <vaibhavedavey@gmail.com>
      30a87a7f
    • Arunprasad Rajkumar's avatar
      Attach source catalog even for follow only mode (#596) · d7a1ea0a
      Arunprasad Rajkumar authored
      
      
      test_decoding transform relies on source catalog to decode the update message.
      
      Prior to this commit, update while using test_decoding would work only while doing `pgcopydb clone --follow`. This commit enables support for update message decoding
      while using test_decoding plugin in `pgcopydb follow` too.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      d7a1ea0a
  3. Dec 20, 2023
  4. Dec 19, 2023
  5. Dec 18, 2023
  6. Dec 15, 2023
    • Dimitri Fontaine's avatar
      Use SQLite to store our internal copy of the source catalogs. (#569) · 27346848
      Dimitri Fontaine authored
      This allows to implement an in-memory array with the capabilities to
      spill-to-disk and also hash-table like lookup operations, and with good
      multi-process concurrency handling.
      
      Using SQLite internally will allow reducing the memory usage of pgcopydb and
      make it possible to address databases with more than a million of tables
      defined.
      27346848
    • Dimitri Fontaine's avatar
      Fix interrupt handling in queue_receive. (#580) · c0b8b459
      Dimitri Fontaine authored
      That allows C-c to work in more situations, which is always good.
      c0b8b459
    • Dimitri Fontaine's avatar
      Fix Postgres connection handling in Large Object related code. (#579) · 3fbb1f61
      Dimitri Fontaine authored
      We would see “WARNING: transaction already in progress” in the logs.
      3fbb1f61
    • Dimitri Fontaine's avatar
      Fix application_name truncation notice messages. (#578) · 13b7290a
      Dimitri Fontaine authored
      Postgres application_name is limited to NAMEDATALEN, sending more bytes
      than that gives us a NOTICE and we can easily avoid it. In passing, avoid
      redundancies in the application_name when the ps_buffer already starts with
      "pgcopydb: ".
      13b7290a
    • Hanefi Onaldi's avatar
      Remove links for indices and tables in docs (#577) · 3f32b1a0
      Hanefi Onaldi authored
      Search page shows 404, whereas genindex and modindex are empty pages.
      3f32b1a0
    • Hanefi Onaldi's avatar
      Add option to output numeric as string on wal2json (#576) · ebe3f332
      Hanefi Onaldi authored
      * Add option to output numeric as string on wal2json
      
      This change adds a new option `--wal2json-numeric-as-string` that
      changes wal2json plugin output format to print numeric data types as
      strings. This is accomplished by passing the
      `--numeric-data-types-as-string` option to wal2json plugin.
      
      This is useful to prevent precision loss when using wal2json
      plugin to stream changes from a database that uses numeric data types.
      
      wal2json plugin version that supports `--numeric-data-types-as-string`
      option is required to use this pgcopydb option. As of today there is no
      official wal2json release that supports this option, but it is available
      on master branch of the project.
      
      Relevant changes in wal2json plugin is at
      https://github.com/eulerto/wal2json/pull/255
      
      * Add env to output numeric as string on wal2json
      
      PGCOPYDB_WAL2JSON_NUMERIC_AS_STRING can be set to a boolean value that
      will be used to determine if pgcopydb should set the wal2json option
      `--numeric-data-types-as-string`.
      
      In passing, also add the PGCOPYDB_OUTPUT_PLUGIN env variable to all
      relevant pages of our documentation.
      ebe3f332
  7. Dec 07, 2023
  8. Dec 06, 2023
    • Arunprasad Rajkumar's avatar
      Compare endpos only if it is valid (#568) · 26260208
      Arunprasad Rajkumar authored
      
      
      Endpos can be set to 0/0 which is an invalid LSN.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      26260208
    • Hanefi Onaldi's avatar
      Parallelize pg_restore operations (#561) · b0e61cae
      Hanefi Onaldi authored
      This commit adds a new option --restore-jobs to pgcopydb that allows
      specifying how many jobs can be used to run pg_restore operations in
      parallel. This option can also be set using the PGCOPYDB_RESTORE_JOBS
      environment variable.
      
      When this option is set to 1, pgcopydb will run pg_restore with the
      --single-transaction option, and pgcopydb will behave the same as it
      used to. Otherwise, pg_restore will be run with the --jobs option set
      to the number of jobs specified by the user.
      
      If the user does not supply the --restore-jobs option, or set the
      environment variable, pgcopydb will use the index-jobs value as default.
      b0e61cae
  9. Dec 05, 2023
    • Shubham Dhama's avatar
      Fix issue where the replay process fails to reach the end position. (#566) · 295f2d17
      Shubham Dhama authored
      In some cases, the replay process doesn't reach the endpos due to a problem
      in the stream process. The problem arises when stream process receives a
      'k' message from wal sender and reaches the endpos. But instead of writing
      the newly received LSN, we write previous LSN with the KEEPALIVE message.
      The following filtered logs from the streaming process illustrate this
      issue.
      
      ```
      endpos is now set to 3/AF01C408
      Reported write_lsn 3/AF01C408, flush_lsn 3/AF01BF38, replay_lsn 3/AF01BF38
      streamFlush: 3/AF01C408 3/AF01C0A0
      Inserted action KEEPALIVE for lsn 3/AF01C0A0 @2023-11-27 11:43:55.946327+0000
      Flushed up to 3/AF01C0A0 in file "cdc/0000000100000003000000AF.json.partial"
      pgsql_stream_logical: endpos reached on keepalive: 3/AF01C5A0
      streamFlush: 3/AF01C5A0 3/AF01C0A0
      Inserted action KEEPALIVE for lsn 3/AF01C0A0 @2023-11-27 11:43:59.754050+0000
      ```
      295f2d17
  10. Dec 02, 2023
    • Arunprasad Rajkumar's avatar
      Fix duplicate key errors on resuming continued txn (#555) · bb2e3e09
      Arunprasad Rajkumar authored
      
      
      This commit addresses and resolves the issue of duplicate key errors when resuming partially executed transactions (continuedTxn) in pgcopydb. We have reintroduced the transaction metadata file, which is essential for identifying the commitLSN of a partial transaction.
      
      Unlike our previous approach, which led to a deadlock between the transform and apply phases, this update brings a more efficient process. Now, the apply phase creates metadata for any partial (continued) transactions during the commit. This metadata is then used to accurately skip the already applied partial transaction if a resume is needed.
      
      This fix is crucial, particularly for tables with unique constraints, where executing the same continued transaction twice previously resulted in duplicate key errors. With this update, pgcopydb ensures smooth and error-free handling of transaction resumes.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      bb2e3e09
  11. Dec 01, 2023
    • Arunprasad Rajkumar's avatar
      Close pipes created by follow after forking childs (#563) · ad196a8d
      Arunprasad Rajkumar authored
      
      
      In the follow process, we create two Unix pipes for bidirectional communication between child processes (prefetch, transform, apply) during replay mode. Each child process closes its unused pipe descriptors upon startup. For example, the prefetch process, which only writes to the transform process, closes the read end of its pipe descriptors immediately.
      
      However, the follow process (parent) itself, which initializes these pipes, does not utilize them for communication. Leaving these pipe descriptors open in the follow process leads to an issue where EOF is not sent, even after the child processes close their ends upon completion. This situation can result in a deadlock, especially when an interruption occurs through Ctrl+C or a SIGTERM signal.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      ad196a8d
    • Hanefi Onaldi's avatar
      Fix one error with formatting in docs (#560) · e6d8628e
      Hanefi Onaldi authored
      In .rst files, the first line of a code block must be empty.  This
      was causing a malformed code block that is hard to read.
      e6d8628e
  12. Nov 30, 2023
    • Gokhan Gulbiz's avatar
      Documentation and Naming Improvements (#556) · 814f9827
      Gokhan Gulbiz authored
      * Update options for pgcopydb snapshot command
      
      * Update options for pgcopydb compare
      
      * Update options for pgcopydb dump subcommands
      
      * Rename create_snapshot_command to snapshot_command
      
      * Capitalize first letters of print and version command descriptions.
      814f9827
    • Hanefi Onaldi's avatar
      Set application name to process title and pid (#553) · 2d97783a
      Hanefi Onaldi authored
      This change makes it easier to identify the connections of pgcopydb in
      pg_stat_activity. The process title contains information on the current
      operation, and the pid of the process is also included in the
      application name. This way we can easily identify the connections of
      pgcopydb in pg_stat_activity even if the process title is truncated.
      2d97783a
    • Shubham Dhama's avatar
      Use same connection in table copy worker. (#542) · 5d6ae50c
      Shubham Dhama authored
      Currently for each table we are creating and closing a new connection to
      the target. Using a same connection would save us some time and resource,
      both at pgcopydb and target side.
      
      Also, seting GUCs only once for a given target connection session would
      again save us resources. This would also reduce 8 extra log lines that are
      currently produced for each table which otherwise would produce noise if we
      have say, 10K tables.
      5d6ae50c
    • Shubham Dhama's avatar
      Fix copying blobs that are not included in snapshot. (#558) · b9288d64
      Shubham Dhama authored
      The issue was that we weren't setting the snapshot for the query that
      fetches the list of large object ids. This inconsistency led to errors when
      trying to access large objects that weren't restored on target.
      
      Error:
      ```
      15:30:11 108 ERROR  [SOURCE 85] ERROR:  large object 16390 does not exist
      15:30:11 108 ERROR  [SOURCE 85] Context: Failed to open large object 16390
      15:30:11 107 ERROR  [SOURCE 83] ERROR:  large object 16392 does not exist
      15:30:11 107 ERROR  [SOURCE 83] Context: Failed to open large object 16392
      ```
      b9288d64
  13. Nov 28, 2023
  14. Nov 27, 2023
    • Arunprasad Rajkumar's avatar
      Fix memory corruption while calling SysV msgsnd & msgrcv (#551) · ac9c72fd
      Arunprasad Rajkumar authored
      
      
      Here is a snippet of man page for msgsnd & msgrcv,
      
      ```
            int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
      
             ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                            int msgflg);
      
      DESCRIPTION
             The  msgsnd() and msgrcv() system calls are used to send messages to, and receive messages from, a System V message queue.  The calling process must have write
             permission on the message queue in order to send a message, and read permission to receive a message.
      
             The msgp argument is a pointer to a caller-defined structure of the following general form:
      
                 struct msgbuf {
                     long mtype;       /* message type, must be > 0 */
                     char mtext[1];    /* message data */
                 };
      
             The mtext field is an array (or other structure) whose size is specified by msgsz, a nonnegative integer value.  Messages of zero length (i.e., no mtext field)
             are  permitted.   The  mtype field must have a strictly positive integer value.  This value can be used by the receiving process for message selection (see the
             description of msgrcv() below).
      ```
      
      According to it, the 3rd arg of both msgsnd and msgrcv must pass the
      size of mtext i.e. excluding the mtype.
      
      If we apply this logic into our context, we must pass the sizeof(QMessage->data), not sizeof(QMessage).
      
      We can also find the corruption using valgrind like below,
      
      ```
      valgrind --trace-children=yes --tool=memcheck --leak-check=no pgcopydb
      copy table-data
      ```
      
      It gives the following summary,
      
      ```
      ==640986== Syscall param msgsnd(msgp->mtext) points to uninitialised byte(s)
      ==640986==    at 0x4AC92AA: msgsnd (msgsnd.c:25)
      ==640986==    by 0x14E178: queue_send (queue_utils.c:100)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:403)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:295)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:232)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:209)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:117)
      ==640986==    by 0x162643: UnknownInlinedFun (table-data.c:89)
      ==640986==    by 0x162643: copydb_copy_all_table_data (table-data.c:57)
      ==640986==    by 0x11406E: cli_copy_table_data (cli_copy.c:395)
      ==640986==    by 0x1118B2: UnknownInlinedFun (commandline.c:71)
      ==640986==    by 0x1118B2: main (main.c:142)
      ==640986==  Address 0x1ffeeec5f0 is on thread 1's stack
      ==640986==  in frame #2, created by copydb_copy_all_table_data (table-data.c:38)
      ==640986==
      ==640986== Syscall param msgsnd(msgp->mtext) points to uninitialised byte(s)
      ==640986==    at 0x4AC92AA: msgsnd (msgsnd.c:25)
      ==640986==    by 0x14E178: queue_send (queue_utils.c:100)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:380)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:307)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:232)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:209)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:117)
      ==640986==    by 0x162AD8: UnknownInlinedFun (table-data.c:89)
      ==640986==    by 0x162AD8: copydb_copy_all_table_data (table-data.c:57)
      ==640986==    by 0x11406E: cli_copy_table_data (cli_copy.c:395)
      ==640986==    by 0x1118B2: UnknownInlinedFun (commandline.c:71)
      ==640986==    by 0x1118B2: main (main.c:142)
      ==640986==  Address 0x1ffeeec5f0 is on thread 1's stack
      ==640986==  in frame #2, created by copydb_copy_all_table_data (table-data.c:38)
      ==640986==
      
      ...
      ```
      
      The above error disappers with the fix.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      ac9c72fd
  15. Nov 23, 2023
    • Hanefi Onaldi's avatar
      Add byte level details to list progress command (#503) · 8ce63dd8
      Hanefi Onaldi authored
      * Add byte level details to list progress command
      
      This patch allows reporting the total number of bytes transferred during
      a copy operation. However, it has a limitation that the reported value
      is only updated after each table is copied. This is because we do not
      update table summary files while the copy is in progress.
      
      Changes include:
      - 3 new fields in table summary structures:
        - network.bytes: total number of bytes transmitted
        - network.bytes-pretty: pretty printed form of network.bytes
        - network.transmit-rate: pretty printed bytes transmitted per second
      - Some new fields on the `pgcopydb list progress --json --summary`
        command:
        - steps[].network is a new field that exists for COPY step and has
          the following fields:
      	- bytes: total number of bytes transmitted for all tables
      	- bytes-pretty: pretty printed form of bytes
        - tables[].network is a new json value with the following fields:
      	- bytes: total number of bytes transmitted for table
      	- bytes-pretty: pretty printed form of bytes
      	- transmit-rate: pretty printed bytes transmitted per second
      - A new column on top level summary that shows total number of bytes
        copied.
      
      * Address reviews
      
      This commit addresses 2 issues raised in the review:
      1. Using a SI standards when reporting data-rate units
      2. Updating the relevant documentation with reproducible examples
      
      The documentation update is done in a way that allowed me to run the
      commands in a docker environment. Once I polish my changes in this
      docker environment, I will update all the documentation with it and
      share it in a separate PR.
      
      * Use bit/s instead of byte/s for data-rate units
      8ce63dd8
  16. Nov 21, 2023
    • Arunprasad Rajkumar's avatar
      Rollback incomplete txns on graceful exit (#544) · c3418105
      Arunprasad Rajkumar authored
      
      
      Before this update, exiting the process (either reaching ENDPOS or user-initiated abort like Ctrl-C) could leave us in the midst of an unfinished transaction. Upon resumption, PostgreSQL begins streaming from a consistent point, which might be the start of this incomplete transaction or from an earlier one. Our previous method tried to bypass all earlier messages until hitting the final message of the incomplete transaction, but this approach had its shortcomings, especially when the messages originated from several transactions back.
      
      This commit introduces a more straightforward solution. Now, if the process is aborted and the last transaction is not complete, we'll issue a rollback command for that transaction. This ensures a clean and consistent state for a graceful exit and subsequent resumption.
      
      Signed-off-by: default avatarArunprasad Rajkumar <ar.arunprasad@gmail.com>
      c3418105