LCOV - code coverage report
Current view: top level - exchangedb - begin_shard.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 81.5 % 27 22
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /*
       2              :    This file is part of TALER
       3              :    Copyright (C) 2022, 2026 Taler Systems SA
       4              : 
       5              :    TALER is free software; you can redistribute it and/or modify it under the
       6              :    terms of the GNU General Public License as published by the Free Software
       7              :    Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :    TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :    You should have received a copy of the GNU General Public License along with
      14              :    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              :  */
      16              : /**
      17              :  * @file exchangedb/begin_shard.c
      18              :  * @brief Implementation of the begin_shard function for Postgres
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/taler_pq_lib.h"
      22              : #include "exchange-database/begin_shard.h"
      23              : #include "helper.h"
      24              : 
      25              : 
      26              : /**
      27              :  * How often do we retry when another worker opened the very shard we were
      28              :  * about to open?  Each round is one round-trip and the loser of the race can
      29              :  * simply take the shard after it, so this converges quickly.
      30              :  */
      31              : #define MAX_RETRIES 10
      32              : 
      33              : 
      34              : enum GNUNET_DB_QueryStatus
      35          300 : TALER_EXCHANGEDB_begin_shard (struct TALER_EXCHANGEDB_PostgresContext *pg,
      36              :                               const char *job_name,
      37              :                               struct GNUNET_TIME_Relative delay,
      38              :                               uint64_t shard_size,
      39              :                               uint64_t *start_row,
      40              :                               uint64_t *end_row,
      41              :                               uint64_t *progress_row)
      42              : {
      43          300 :   PREPARE (pg,
      44              :            "begin_shard",
      45              :            "SELECT"
      46              :            " out_start_row"
      47              :            ",out_end_row"
      48              :            ",out_progress_row"
      49              :            " FROM exchange_do_begin_shard"
      50              :            " ($1,$2,$3,$4);");
      51          300 :   for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
      52              :   {
      53              :     struct GNUNET_TIME_Absolute now
      54          300 :       = GNUNET_TIME_absolute_get ();
      55              :     struct GNUNET_TIME_Absolute lease_until
      56          300 :       = GNUNET_TIME_relative_to_absolute (delay);
      57          300 :     struct GNUNET_PQ_QueryParam params[] = {
      58          300 :       GNUNET_PQ_query_param_string (job_name),
      59          300 :       GNUNET_PQ_query_param_absolute_time (&now),
      60          300 :       GNUNET_PQ_query_param_absolute_time (&lease_until),
      61          300 :       GNUNET_PQ_query_param_uint64 (&shard_size),
      62              :       GNUNET_PQ_query_param_end
      63              :     };
      64          300 :     bool lost_race = false;
      65          300 :     struct GNUNET_PQ_ResultSpec rs[] = {
      66          300 :       GNUNET_PQ_result_spec_allow_null (
      67              :         GNUNET_PQ_result_spec_uint64 ("out_start_row",
      68              :                                       start_row),
      69              :         &lost_race),
      70          300 :       GNUNET_PQ_result_spec_allow_null (
      71              :         GNUNET_PQ_result_spec_uint64 ("out_end_row",
      72              :                                       end_row),
      73              :         NULL),
      74          300 :       GNUNET_PQ_result_spec_allow_null (
      75              :         GNUNET_PQ_result_spec_uint64 ("out_progress_row",
      76              :                                       progress_row),
      77              :         NULL),
      78              :       GNUNET_PQ_result_spec_end
      79              :     };
      80              :     enum GNUNET_DB_QueryStatus qs;
      81              : 
      82          300 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
      83              :                                                    "begin_shard",
      84              :                                                    params,
      85              :                                                    rs);
      86          300 :     if (0 > qs)
      87          300 :       return qs;
      88          300 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
      89              :     {
      90            0 :       GNUNET_break (0); /* the function always returns exactly one row */
      91            0 :       return GNUNET_DB_STATUS_HARD_ERROR;
      92              :     }
      93          300 :     if (lost_race)
      94              :     {
      95              :       /* Someone else opened the shard we picked.  Go around: either take over
      96              :          an even older one, or open the one after theirs. */
      97            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
      98              :                   "Lost the race to open a shard of %s, trying again\n",
      99              :                   job_name);
     100            0 :       continue;
     101              :     }
     102          300 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     103              :                 "Acquired shard %s (%llu,%llu], resuming at %llu\n",
     104              :                 job_name,
     105              :                 (unsigned long long) *start_row,
     106              :                 (unsigned long long) *end_row,
     107              :                 (unsigned long long) *progress_row);
     108          300 :     return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     109              :   }
     110              :   /* Persistent contention.  Not an error, but the caller should back off. */
     111            0 :   return GNUNET_DB_STATUS_SOFT_ERROR;
     112              : }
        

Generated by: LCOV version 2.0-1