LCOV - code coverage report
Current view: top level - gdk - gdk_logger_old.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 262 1031 25.4 %
Date: 2021-09-14 19:48:19 Functions: 12 43 27.9 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (author) N. J. Nes
      11             :  *
      12             :  * In the philosophy of MonetDB, transaction management overhead
      13             :  * should only be paid when necessary. Transaction management is for
      14             :  * this purpose implemented as a separate module and applications are
      15             :  * required to obey the transaction policy, e.g. obtaining/releasing
      16             :  * locks.
      17             :  *
      18             :  * This module is designed to support efficient logging of the SQL
      19             :  * database.  Once loaded, the SQL compiler will insert the proper
      20             :  * calls at transaction commit to include the changes in the log file.
      21             :  *
      22             :  * The logger uses a directory to store its log files. One master log
      23             :  * file stores information about the version of the logger and the
      24             :  * transaction log files. This file is a simple ascii file with the
      25             :  * following format:
      26             :  *  {6DIGIT-VERSION\n[log file number \n]*]*}
      27             :  * The transaction log files have a binary format, which stores fixed
      28             :  * size logformat headers (flag,nr,bid), where the flag is the type of
      29             :  * update logged.  The nr field indicates how many changes there were
      30             :  * (in case of inserts/deletes).  The bid stores the bid identifier.
      31             :  *
      32             :  * The key decision to be made by the user is the location of the log
      33             :  * file.  Ideally, it should be stored in fail-safe environment, or at
      34             :  * least the log and databases should be on separate disk columns.
      35             :  *
      36             :  * This file system may reside on the same hardware as the database
      37             :  * server and therefore the writes are done to the same disk, but
      38             :  * could also reside on another system and then the changes are
      39             :  * flushed through the network.  The logger works under the assumption
      40             :  * that it is called to safeguard updates on the database when it has
      41             :  * an exclusive lock on the latest version. This lock should be
      42             :  * guaranteed by the calling transaction manager first.
      43             :  *
      44             :  * Finding the updates applied to a BAT is relatively easy, because
      45             :  * each BAT contains a delta structure. On commit these changes are
      46             :  * written to the log file and the delta management is reset. Since
      47             :  * each commit is written to the same log file, the beginning and end
      48             :  * are marked by a log identifier.
      49             :  *
      50             :  * A server restart should only (re)process blocks which are
      51             :  * completely written to disk. A log replay therefore ends in a commit
      52             :  * or abort on the changed bats. Once all logs have been read, the
      53             :  * changes to the bats are made persistent, i.e. a bbp sub-commit is
      54             :  * done.
      55             :  */
      56             : #include "monetdb_config.h"
      57             : #include "gdk.h"
      58             : #include "gdk_private.h"
      59             : #include "gdk_logger.h"
      60             : #include "gdk_logger_internals.h"
      61             : #include "mutils.h"
      62             : #include <string.h>
      63             : 
      64             : /*
      65             :  * The log record encoding is geared at reduced storage space, but at
      66             :  * the expense of readability. A user can not easily inspect the log a
      67             :  * posteriori to check what has happened.
      68             :  *
      69             :  */
      70             : #define LOG_START       1
      71             : #define LOG_END         2
      72             : #define LOG_INSERT      3
      73             : #define LOG_UPDATE      5
      74             : #define LOG_CREATE      6
      75             : #define LOG_DESTROY     7
      76             : #define LOG_USE         8
      77             : #define LOG_CLEAR       9
      78             : #define LOG_SEQ         10
      79             : #define LOG_INSERT_ID   11
      80             : #define LOG_UPDATE_ID   12
      81             : #define LOG_CREATE_ID   13
      82             : #define LOG_DESTROY_ID  14
      83             : #define LOG_USE_ID      15
      84             : #define LOG_CLEAR_ID    16
      85             : #define LOG_UPDATE_PAX  17
      86             : 
      87             : #ifdef NATIVE_WIN32
      88             : #define getfilepos _ftelli64
      89             : #else
      90             : #ifdef HAVE_FSEEKO
      91             : #define getfilepos ftello
      92             : #else
      93             : #define getfilepos ftell
      94             : #endif
      95             : #endif
      96             : 
      97             : #define BATSIZE 0
      98             : 
      99             : #define NAME(name,tpe,id) (name?name:"tpe id")
     100             : 
     101             : #define LOG_DISABLED(lg) ((lg)->lg->debug&128)
     102             : 
     103             : static gdk_return logger_cleanup(old_logger *lg);
     104             : static gdk_return logger_add_bat(old_logger *lg, BAT *b, const char *name, char tpe, oid id);
     105             : static gdk_return logger_del_bat(old_logger *lg, log_bid bid);
     106             : 
     107             : static const char *log_commands[] = {
     108             :         NULL,
     109             :         "LOG_START",
     110             :         "LOG_END",
     111             :         "LOG_INSERT",
     112             :         "LOG_DELETE",
     113             :         "LOG_UPDATE",
     114             :         "LOG_CREATE",
     115             :         "LOG_DESTROY",
     116             :         "LOG_USE",
     117             :         "LOG_CLEAR",
     118             :         "LOG_SEQ",
     119             :         "LOG_INSERT_ID",
     120             :         "LOG_DELETE_ID",
     121             :         "LOG_UPDATE_ID",
     122             :         "LOG_CREATE_ID",
     123             :         "LOG_DESTROY_ID",
     124             :         "LOG_USE_ID",
     125             :         "LOG_CLEAR_ID",
     126             :         "LOG_UPDATE_PAX",
     127             : };
     128             : 
     129             : typedef struct logaction {
     130             :         int type;               /* type of change */
     131             :         lng nr;
     132             :         int ht;                 /* vid(-1),void etc */
     133             :         int tt;
     134             :         lng id;
     135             :         char *name;             /* optional */
     136             :         char tpe;               /* tpe of column */
     137             :         oid cid;                /* id of object */
     138             :         BAT *b;                 /* temporary bat with changes */
     139             :         BAT *uid;               /* temporary bat with bun positions to update */
     140             : } logaction;
     141             : 
     142             : /* during the recover process a number of transactions could be active */
     143             : typedef struct trans {
     144             :         int tid;                /* transaction id */
     145             :         int sz;                 /* sz of the changes array */
     146             :         int nr;                 /* nr of changes */
     147             : 
     148             :         logaction *changes;
     149             : 
     150             :         struct trans *tr;
     151             : } trans;
     152             : 
     153             : typedef struct logformat_t {
     154             :         char flag;
     155             :         int tid;
     156             :         lng nr;
     157             : } logformat;
     158             : 
     159             : typedef enum {LOG_OK, LOG_EOF, LOG_ERR} log_return;
     160             : 
     161             : #include "gdk_geomlogger.h"
     162             : 
     163             : /* When reading an old format database, we may need to read the geom
     164             :  * Well-known Binary (WKB) type differently.  This variable is used to
     165             :  * indicate that to the function wkbREAD during reading of the log. */
     166             : static bool geomisoldversion;
     167             : 
     168             : static gdk_return tr_grow(trans *tr);
     169             : 
     170             : static BUN
     171           0 : log_find(BAT *b, BAT *d, int val)
     172             : {
     173           0 :         BATiter cni = bat_iterator_nolock(b);
     174             :         BUN p;
     175             : 
     176           0 :         assert(b->ttype == TYPE_int);
     177           0 :         assert(d->ttype == TYPE_oid);
     178           0 :         if (BAThash(b) == GDK_SUCCEED) {
     179           0 :                 MT_rwlock_rdlock(&cni.b->thashlock);
     180           0 :                 HASHloop_int(cni, cni.b->thash, p, &val) {
     181           0 :                         oid pos = p;
     182           0 :                         if (BUNfnd(d, &pos) == BUN_NONE) {
     183           0 :                                 MT_rwlock_rdunlock(&cni.b->thashlock);
     184           0 :                                 return p;
     185             :                         }
     186             :                 }
     187           0 :                 MT_rwlock_rdunlock(&cni.b->thashlock);
     188             :         } else {                /* unlikely: BAThash failed */
     189             :                 BUN q;
     190           0 :                 int *t = (int *) Tloc(b, 0);
     191             : 
     192           0 :                 for (p = 0, q = BUNlast(b); p < q; p++) {
     193           0 :                         if (t[p] == val) {
     194           0 :                                 oid pos = p;
     195           0 :                                 if (BUNfnd(d, &pos) == BUN_NONE) {
     196           0 :                                         return p;
     197             :                                 }
     198             :                         }
     199             :                 }
     200             :         }
     201             :         return BUN_NONE;
     202             : }
     203             : 
     204             : static void
     205             : logbat_destroy(BAT *b)
     206             : {
     207           0 :         if (b)
     208         112 :                 BBPunfix(b->batCacheid);
     209           0 : }
     210             : 
     211             : static BAT *
     212           8 : logbat_new(int tt, BUN size, role_t role)
     213             : {
     214           8 :         BAT *nb = COLnew(0, tt, size, role);
     215             : 
     216           8 :         if (nb) {
     217           8 :                 if (role == PERSISTENT)
     218           0 :                         BATmode(nb, false);
     219             :         } else {
     220           0 :                 TRC_CRITICAL(GDK, "creating new BAT[void:%s]#" BUNFMT " failed\n", ATOMname(tt), size);
     221             :         }
     222           8 :         return nb;
     223             : }
     224             : 
     225             : static int
     226          23 : log_read_format(old_logger *l, logformat *data)
     227             : {
     228          23 :         return mnstr_read(l->log, &data->flag, 1, 1) == 1 &&
     229          23 :                 mnstr_readLng(l->log, &data->nr) == 1 &&
     230           0 :                 mnstr_readInt(l->log, &data->tid) == 1;
     231             : }
     232             : 
     233             : static char *
     234           0 : log_read_string(old_logger *l)
     235             : {
     236             :         int len;
     237             :         ssize_t nr;
     238             :         char *buf;
     239             : 
     240           0 :         if (mnstr_readInt(l->log, &len) != 1) {
     241           0 :                 TRC_CRITICAL(GDK, "read failed\n");
     242             : //MK This leads to non-repeatable log structure?
     243           0 :                 return NULL;
     244             :         }
     245           0 :         if (len == 0)
     246             :                 return NULL;
     247           0 :         buf = GDKmalloc(len);
     248           0 :         if (buf == NULL) {
     249           0 :                 TRC_CRITICAL(GDK, "malloc failed\n");
     250             :                 /* this is bad */
     251           0 :                 return (char *) -1;
     252             :         }
     253             : 
     254           0 :         if ((nr = mnstr_read(l->log, buf, 1, len)) != (ssize_t) len) {
     255           0 :                 buf[len - 1] = 0;
     256           0 :                 TRC_CRITICAL(GDK, "couldn't read name (%s) %zd\n", buf, nr);
     257           0 :                 GDKfree(buf);
     258           0 :                 return NULL;
     259             :         }
     260           0 :         buf[len - 1] = 0;
     261           0 :         return buf;
     262             : }
     263             : 
     264             : static log_return
     265           0 : log_read_clear(old_logger *lg, trans *tr, char *name, char tpe, oid id)
     266             : {
     267           0 :         if (lg->lg->debug & 1)
     268           0 :                 fprintf(stderr, "#logger found log_read_clear %s\n", NAME(name, tpe, id));
     269           0 :         if (tr_grow(tr) != GDK_SUCCEED)
     270             :                 return LOG_ERR;
     271           0 :         tr->changes[tr->nr].type = LOG_CLEAR;
     272           0 :         tr->changes[tr->nr].tpe = tpe;
     273           0 :         tr->changes[tr->nr].cid = id;
     274           0 :         if (name && (tr->changes[tr->nr].name = GDKstrdup(name)) == NULL)
     275             :                 return LOG_ERR;
     276           0 :         tr->nr++;
     277           0 :         return LOG_OK;
     278             : }
     279             : 
     280             : static int
     281           0 : avoid_snapshot(old_logger *lg, log_bid bid)
     282             : {
     283           0 :         if (BATcount(lg->snapshots_bid)-BATcount(lg->dsnapshots)) {
     284           0 :                 BUN p = log_find(lg->snapshots_bid, lg->dsnapshots, bid);
     285             : 
     286           0 :                 if (p != BUN_NONE) {
     287           0 :                         int tid = *(int *) Tloc(lg->snapshots_tid, p);
     288             : 
     289           0 :                         if (lg->tid <= tid)
     290           0 :                                 return 1;
     291             :                 }
     292             :         }
     293             :         return 0;
     294             : }
     295             : 
     296             : log_bid
     297        1512 : old_logger_find_bat(old_logger *lg, const char *name, char tpe, oid id)
     298             : {
     299        1884 :         if (!tpe || !lg->with_ids) {
     300        1512 :                 BATiter cni = bat_iterator_nolock(lg->catalog_nme);
     301             :                 BUN p;
     302             : 
     303        1512 :                 if (BAThash(lg->catalog_nme) == GDK_SUCCEED) {
     304        1512 :                         MT_rwlock_rdlock(&cni.b->thashlock);
     305        3244 :                         HASHloop_str(cni, cni.b->thash, p, name) {
     306        1140 :                                 oid pos = p;
     307        1140 :                                 if (BUNfnd(lg->dcatalog, &pos) == BUN_NONE) {
     308        1140 :                                         oid lid = *(oid*) Tloc(lg->catalog_oid, p);
     309        1140 :                                         if (!lid) {
     310        1140 :                                                 MT_rwlock_rdunlock(&cni.b->thashlock);
     311        1140 :                                                 return *(log_bid *) Tloc(lg->catalog_bid, p);
     312             :                                         }
     313             :                                 }
     314             :                         }
     315         372 :                         MT_rwlock_rdunlock(&cni.b->thashlock);
     316             :                 }
     317             :         } else {
     318           0 :                 BATiter cni = bat_iterator_nolock(lg->catalog_oid);
     319             :                 BUN p;
     320             : 
     321           0 :                 if (BAThash(lg->catalog_oid) == GDK_SUCCEED) {
     322           0 :                         lng lid = (lng) id;
     323           0 :                         MT_rwlock_rdlock(&cni.b->thashlock);
     324           0 :                         HASHloop_lng(cni, cni.b->thash, p, &lid) {
     325           0 :                                 oid pos = p;
     326           0 :                                 if (*(char*)Tloc(lg->catalog_tpe, p) == tpe) {
     327           0 :                                         if (BUNfnd(lg->dcatalog, &pos) == BUN_NONE) {
     328           0 :                                                 MT_rwlock_rdunlock(&cni.b->thashlock);
     329           0 :                                                 return *(log_bid *) Tloc(lg->catalog_bid, p);
     330             :                                         }
     331             :                                 }
     332             :                         }
     333           0 :                         MT_rwlock_rdunlock(&cni.b->thashlock);
     334             :                 }
     335             :         }
     336             :         return 0;
     337             : }
     338             : 
     339             : static gdk_return
     340           0 : la_bat_clear(old_logger *lg, logaction *la)
     341             : {
     342           0 :         log_bid bid = old_logger_find_bat(lg, la->name, la->tpe, la->cid);
     343             :         BAT *b;
     344             : 
     345           0 :         if (lg->lg->debug & 1)
     346           0 :                 fprintf(stderr, "#la_bat_clear %s\n", NAME(la->name, la->tpe, la->cid));
     347             : 
     348             :         /* do we need to skip these old updates */
     349           0 :         if (avoid_snapshot(lg, bid))
     350             :                 return GDK_SUCCEED;
     351             : 
     352           0 :         b = BATdescriptor(bid);
     353           0 :         if (b) {
     354           0 :                 restrict_t access = (restrict_t) b->batRestricted;
     355           0 :                 b->batRestricted = BAT_WRITE;
     356           0 :                 BATclear(b, true);
     357           0 :                 b->batRestricted = access;
     358             :                 logbat_destroy(b);
     359             :         }
     360             :         return GDK_SUCCEED;
     361             : }
     362             : 
     363             : static log_return
     364           0 : log_read_seq(old_logger *lg, logformat *l)
     365             : {
     366           0 :         int seq = (int) l->nr;
     367             :         lng val;
     368             :         BUN p;
     369             : 
     370           0 :         assert(l->nr <= (lng) INT_MAX);
     371           0 :         if (mnstr_readLng(lg->log, &val) != 1) {
     372           0 :                 TRC_CRITICAL(GDK, "read failed\n");
     373           0 :                 return LOG_EOF;
     374             :         }
     375             : 
     376           0 :         if ((p = log_find(lg->seqs_id, lg->dseqs, seq)) != BUN_NONE &&
     377           0 :             p >= lg->seqs_id->batInserted) {
     378           0 :                 assert(lg->seqs_val->hseqbase == 0);
     379           0 :                 if (BUNreplace(lg->seqs_val, p, &val, false) != GDK_SUCCEED)
     380           0 :                         return LOG_ERR;
     381             :         } else {
     382           0 :                 if (p != BUN_NONE) {
     383           0 :                         oid pos = p;
     384           0 :                         if (BUNappend(lg->dseqs, &pos, false) != GDK_SUCCEED)
     385           0 :                                 return LOG_ERR;
     386             :                 }
     387           0 :                 if (BUNappend(lg->seqs_id, &seq, false) != GDK_SUCCEED ||
     388           0 :                     BUNappend(lg->seqs_val, &val, false) != GDK_SUCCEED)
     389           0 :                         return LOG_ERR;
     390             :         }
     391             :         return LOG_OK;
     392             : }
     393             : 
     394             : static int
     395           0 : log_read_id(old_logger *lg, char *tpe, oid *id)
     396             : {
     397             :         lng lid;
     398             : 
     399           0 :         if (mnstr_readChr(lg->log, tpe) != 1 ||
     400           0 :             mnstr_readLng(lg->log, &lid) != 1) {
     401           0 :                 TRC_CRITICAL(GDK, "read failed\n");
     402           0 :                 return LOG_EOF;
     403             :         }
     404           0 :         *id = (oid)lid;
     405           0 :         return LOG_OK;
     406             : }
     407             : 
     408             : static log_return
     409           0 : log_read_updates(old_logger *lg, trans *tr, logformat *l, char *name, int tpe, oid id, int pax)
     410             : {
     411           0 :         log_bid bid = old_logger_find_bat(lg, name, tpe, id);
     412           0 :         BAT *b = BATdescriptor(bid);
     413             :         log_return res = LOG_OK;
     414             :         int ht = -1, tt = -1, tseq = 0;
     415             : 
     416           0 :         if (lg->lg->debug & 1) {
     417           0 :                 if (name)
     418           0 :                         fprintf(stderr, "#logger found log_read_updates %s %s " LLFMT "\n", name, l->flag == LOG_INSERT ? "insert" : "update", l->nr);
     419             :                 else
     420           0 :                         fprintf(stderr, "#logger found log_read_updates " OIDFMT " %s " LLFMT "\n", id, l->flag == LOG_INSERT ? "insert" : "update", l->nr);
     421             :         }
     422             : 
     423           0 :         if (b) {
     424             :                 ht = TYPE_void;
     425           0 :                 tt = b->ttype;
     426           0 :                 if (tt == TYPE_void && BATtdense(b))
     427             :                         tseq = 1;
     428             :         } else {                /* search trans action for create statement */
     429             :                 int i;
     430             : 
     431           0 :                 for (i = 0; i < tr->nr; i++) {
     432           0 :                         if (tr->changes[i].type == LOG_CREATE &&
     433           0 :                             (tpe == 0 && name != NULL
     434           0 :                              ? strcmp(tr->changes[i].name, name) == 0
     435           0 :                              : tr->changes[i].tpe == tpe && tr->changes[i].cid == id)) {
     436           0 :                                 ht = tr->changes[i].ht;
     437             :                                 if (ht < 0) {
     438             :                                         ht = TYPE_void;
     439             :                                 }
     440           0 :                                 tt = tr->changes[i].tt;
     441           0 :                                 if (tt < 0) {
     442             :                                         tseq = 1;
     443             :                                         tt = TYPE_void;
     444             :                                 }
     445             :                                 break;
     446           0 :                         } else if (tr->changes[i].type == LOG_USE &&
     447           0 :                                    (tpe == 0 && name != NULL
     448           0 :                                     ? strcmp(tr->changes[i].name, name) == 0
     449           0 :                                     : tr->changes[i].tpe == tpe && tr->changes[i].cid == id)) {
     450           0 :                                 log_bid bid = (log_bid) tr->changes[i].nr;
     451           0 :                                 BAT *b = BATdescriptor(bid);
     452             : 
     453           0 :                                 if (b) {
     454             :                                         ht = TYPE_void;
     455           0 :                                         tt = b->ttype;
     456             :                                 }
     457             :                                 break;
     458             :                         }
     459             :                 }
     460           0 :                 assert(i < tr->nr); /* found one */
     461             :         }
     462           0 :         assert((ht == TYPE_void && l->flag == LOG_INSERT) ||
     463             :                ((ht == TYPE_oid || !ht) && l->flag == LOG_UPDATE));
     464           0 :         if ((ht != TYPE_void && l->flag == LOG_INSERT) ||
     465           0 :            ((ht != TYPE_void && ht != TYPE_oid) && l->flag == LOG_UPDATE))
     466             :                 return LOG_ERR;
     467           0 :         if (ht >= 0 && tt >= 0) {
     468             :                 BAT *uid = NULL;
     469             :                 BAT *r;
     470           0 :                 void *(*rt) (ptr, size_t *, stream *, size_t) = BATatoms[tt].atomRead;
     471             : 
     472           0 :                 assert(l->nr <= (lng) BUN_MAX);
     473           0 :                 if (l->flag == LOG_UPDATE) {
     474           0 :                         uid = COLnew(0, ht, (BUN) l->nr, PERSISTENT);
     475           0 :                         if (uid == NULL) {
     476             :                                 logbat_destroy(b);
     477           0 :                                 return LOG_ERR;
     478             :                         }
     479             :                 } else {
     480           0 :                         assert(ht == TYPE_void);
     481             :                 }
     482           0 :                 r = COLnew(0, tt, (BUN) l->nr, PERSISTENT);
     483           0 :                 if (r == NULL) {
     484           0 :                         BBPreclaim(uid);
     485             :                         logbat_destroy(b);
     486           0 :                         return LOG_ERR;
     487             :                 }
     488             : 
     489           0 :                 if (tseq)
     490           0 :                         BATtseqbase(r, 0);
     491             : 
     492           0 :                 if (ht == TYPE_void && l->flag == LOG_INSERT) {
     493           0 :                         lng nr = l->nr;
     494           0 :                         for (; res == LOG_OK && nr > 0; nr--) {
     495           0 :                                 size_t tlen = lg->lg->bufsize;
     496           0 :                                 void *t = rt(lg->lg->buf, &tlen, lg->log, 1);
     497             : 
     498           0 :                                 if (t == NULL) {
     499             :                                         /* see if failure was due to
     500             :                                          * malloc or something less
     501             :                                          * serious (in the current
     502             :                                          * context) */
     503           0 :                                         if (strstr(GDKerrbuf, "alloc") == NULL)
     504             :                                                 res = LOG_EOF;
     505             :                                         else
     506             :                                                 res = LOG_ERR;
     507           0 :                                         break;
     508             :                                 } else {
     509           0 :                                         lg->lg->buf = t;
     510           0 :                                         lg->lg->bufsize = tlen;
     511             :                                 }
     512           0 :                                 if (BUNappend(r, t, true) != GDK_SUCCEED)
     513             :                                         res = LOG_ERR;
     514             :                         }
     515             :                 } else {
     516           0 :                         void *(*rh) (ptr, size_t *, stream *, size_t) = ht == TYPE_void ? BATatoms[TYPE_oid].atomRead : BATatoms[ht].atomRead;
     517           0 :                         void *hv = ATOMnil(ht);
     518           0 :                         size_t hlen = ATOMsize(ht);
     519             : 
     520           0 :                         if (hv == NULL)
     521             :                                 res = LOG_ERR;
     522             : 
     523           0 :                         if (!pax) {
     524           0 :                                 lng nr = l->nr;
     525           0 :                                 for (; res == LOG_OK && nr > 0; nr--) {
     526           0 :                                         size_t tlen = lg->lg->bufsize;
     527           0 :                                         void *h = rh(hv, &hlen, lg->log, 1);
     528           0 :                                         void *t = rt(lg->lg->buf, &tlen, lg->log, 1);
     529             : 
     530           0 :                                         if (t != NULL) {
     531           0 :                                                 lg->lg->buf = t;
     532           0 :                                                 lg->lg->bufsize = tlen;
     533             :                                         }
     534           0 :                                         if (h == NULL)
     535             :                                                 res = LOG_EOF;
     536           0 :                                         else if (t == NULL) {
     537           0 :                                                 if (strstr(GDKerrbuf, "malloc") == NULL)
     538             :                                                         res = LOG_EOF;
     539             :                                                 else
     540             :                                                         res = LOG_ERR;
     541           0 :                                         } else if (BUNappend(uid, h, true) != GDK_SUCCEED ||
     542           0 :                                                 BUNappend(r, t, true) != GDK_SUCCEED)
     543             :                                                 res = LOG_ERR;
     544             :                                 }
     545             :                         } else {
     546           0 :                                 char compressed = 0;
     547           0 :                                 lng nr = l->nr;
     548             : 
     549           0 :                                 if (mnstr_read(lg->log, &compressed, 1, 1) != 1)
     550           0 :                                         return LOG_ERR;
     551             : 
     552           0 :                                 if (compressed) {
     553           0 :                                         void *h = rh(hv, &hlen, lg->log, 1);
     554             : 
     555           0 :                                         assert(uid->ttype == TYPE_void);
     556           0 :                                         if (h == NULL)
     557             :                                                 res = LOG_EOF;
     558             :                                         else {
     559           0 :                                                 BATtseqbase(uid, *(oid*)h);
     560           0 :                                                 BATsetcount(uid, (BUN) l->nr);
     561             :                                         }
     562             :                                 } else {
     563           0 :                                         for (; res == LOG_OK && nr > 0; nr--) {
     564           0 :                                                 void *h = rh(hv, &hlen, lg->log, 1);
     565             : 
     566           0 :                                                 if (h == NULL)
     567             :                                                         res = LOG_EOF;
     568           0 :                                                 else if (BUNappend(uid, h, true) != GDK_SUCCEED)
     569             :                                                         res = LOG_ERR;
     570             :                                         }
     571             :                                 }
     572           0 :                                 nr = l->nr;
     573           0 :                                 for (; res == LOG_OK && nr > 0; nr--) {
     574           0 :                                         size_t tlen = lg->lg->bufsize;
     575           0 :                                         void *t = rt(lg->lg->buf, &tlen, lg->log, 1);
     576             : 
     577           0 :                                         if (t == NULL) {
     578           0 :                                                 if (strstr(GDKerrbuf, "malloc") == NULL)
     579             :                                                         res = LOG_EOF;
     580             :                                                 else
     581             :                                                         res = LOG_ERR;
     582             :                                         } else {
     583           0 :                                                 lg->lg->buf = t;
     584           0 :                                                 lg->lg->bufsize = tlen;
     585           0 :                                                 if (BUNappend(r, t, true) != GDK_SUCCEED)
     586             :                                                         res = LOG_ERR;
     587             :                                         }
     588             :                                 }
     589             :                         }
     590           0 :                         GDKfree(hv);
     591             :                 }
     592             : 
     593           0 :                 if (res == LOG_OK) {
     594           0 :                         if (tr_grow(tr) == GDK_SUCCEED) {
     595           0 :                                 tr->changes[tr->nr].type = l->flag;
     596           0 :                                 tr->changes[tr->nr].nr = l->nr;
     597           0 :                                 tr->changes[tr->nr].ht = ht;
     598           0 :                                 tr->changes[tr->nr].tt = tt;
     599           0 :                                 tr->changes[tr->nr].tpe = tpe;
     600           0 :                                 tr->changes[tr->nr].cid = id;
     601           0 :                                 if (name && (tr->changes[tr->nr].name = GDKstrdup(name)) == NULL) {
     602             :                                         logbat_destroy(b);
     603           0 :                                         BBPreclaim(uid);
     604           0 :                                         BBPreclaim(r);
     605           0 :                                         return LOG_ERR;
     606             :                                 }
     607           0 :                                 tr->changes[tr->nr].b = r;
     608           0 :                                 tr->changes[tr->nr].uid = uid;
     609           0 :                                 tr->nr++;
     610             :                         } else {
     611             :                                 res = LOG_ERR;
     612             :                         }
     613             :                 }
     614             :         } else {
     615             :                 /* bat missing ERROR or ignore ? currently error. */
     616             :                 res = LOG_ERR;
     617             :         }
     618             :         logbat_destroy(b);
     619             :         return res;
     620             : }
     621             : 
     622             : static gdk_return
     623           0 : la_bat_updates(old_logger *lg, logaction *la)
     624             : {
     625           0 :         log_bid bid = old_logger_find_bat(lg, la->name, la->tpe, la->cid);
     626             :         BAT *b;
     627             : 
     628           0 :         if (bid == 0)
     629             :                 return GDK_SUCCEED; /* ignore bats no longer in the catalog */
     630             : 
     631             :         /* do we need to skip these old updates */
     632           0 :         if (avoid_snapshot(lg, bid))
     633             :                 return GDK_SUCCEED;
     634             : 
     635           0 :         b = BATdescriptor(bid);
     636           0 :         if (b == NULL)
     637             :                 return GDK_FAIL;
     638           0 :         if (la->type == LOG_INSERT) {
     639           0 :                 if (BATappend(b, la->b, NULL, true) != GDK_SUCCEED) {
     640             :                         logbat_destroy(b);
     641           0 :                         return GDK_FAIL;
     642             :                 }
     643           0 :         } else if (la->type == LOG_UPDATE) {
     644           0 :                 BATiter vi = bat_iterator(la->b);
     645             :                 BUN p, q;
     646             : 
     647           0 :                 BATloop(la->b, p, q) {
     648           0 :                         oid h = BUNtoid(la->uid, p);
     649           0 :                         const void *t = BUNtail(vi, p);
     650             : 
     651           0 :                         if (h < b->hseqbase || h >= b->hseqbase + BATcount(b)) {
     652             :                                 /* if value doesn't exist, insert it;
     653             :                                  * if b void headed, maintain that by
     654             :                                  * inserting nils */
     655           0 :                                 if (b->batCount == 0 && !is_oid_nil(h))
     656           0 :                                         b->hseqbase = h;
     657           0 :                                 if (!is_oid_nil(b->hseqbase) && !is_oid_nil(h)) {
     658           0 :                                         const void *tv = ATOMnilptr(b->ttype);
     659             : 
     660           0 :                                         while (b->hseqbase + b->batCount < h) {
     661           0 :                                                 if (BUNappend(b, tv, true) != GDK_SUCCEED) {
     662             :                                                         logbat_destroy(b);
     663           0 :                                                         bat_iterator_end(&vi);
     664           0 :                                                         return GDK_FAIL;
     665             :                                                 }
     666             :                                         }
     667             :                                 }
     668           0 :                                 if (BUNappend(b, t, true) != GDK_SUCCEED) {
     669             :                                         logbat_destroy(b);
     670           0 :                                         bat_iterator_end(&vi);
     671           0 :                                         return GDK_FAIL;
     672             :                                 }
     673             :                         } else {
     674           0 :                                 if (BUNreplace(b, h, t, true) != GDK_SUCCEED) {
     675             :                                         logbat_destroy(b);
     676           0 :                                         bat_iterator_end(&vi);
     677           0 :                                         return GDK_FAIL;
     678             :                                 }
     679             :                         }
     680             :                 }
     681           0 :                 bat_iterator_end(&vi);
     682             :         }
     683             :         logbat_destroy(b);
     684           0 :         return GDK_SUCCEED;
     685             : }
     686             : 
     687             : static log_return
     688           0 : log_read_destroy(old_logger *lg, trans *tr, char *name, char tpe, oid id)
     689             : {
     690             :         (void) lg;
     691           0 :         if (tr_grow(tr) == GDK_SUCCEED) {
     692           0 :                 tr->changes[tr->nr].type = LOG_DESTROY;
     693           0 :                 tr->changes[tr->nr].tpe = tpe;
     694           0 :                 tr->changes[tr->nr].cid = id;
     695           0 :                 if (name && (tr->changes[tr->nr].name = GDKstrdup(name)) == NULL)
     696             :                         return LOG_ERR;
     697           0 :                 tr->nr++;
     698             :         }
     699             :         return LOG_OK;
     700             : }
     701             : 
     702             : static gdk_return
     703           0 : la_bat_destroy(old_logger *lg, logaction *la)
     704             : {
     705           0 :         log_bid bid = old_logger_find_bat(lg, la->name, la->tpe, la->cid);
     706             : 
     707           0 :         if (bid) {
     708             :                 BUN p;
     709             : 
     710           0 :                 if (logger_del_bat(lg, bid) != GDK_SUCCEED)
     711             :                         return GDK_FAIL;
     712             : 
     713           0 :                 if ((p = log_find(lg->snapshots_bid, lg->dsnapshots, bid)) != BUN_NONE) {
     714           0 :                         oid pos = (oid) p;
     715             : #ifndef NDEBUG
     716           0 :                         assert(BBP_desc(bid)->batRole == PERSISTENT);
     717           0 :                         assert(0 <= BBP_desc(bid)->theap->farmid && BBP_desc(bid)->theap->farmid < MAXFARMS);
     718           0 :                         assert(BBPfarms[BBP_desc(bid)->theap->farmid].roles & (1 << PERSISTENT));
     719           0 :                         if (BBP_desc(bid)->tvheap) {
     720           0 :                                 assert(0 <= BBP_desc(bid)->tvheap->farmid && BBP_desc(bid)->tvheap->farmid < MAXFARMS);
     721           0 :                                 assert(BBPfarms[BBP_desc(bid)->tvheap->farmid].roles & (1 << PERSISTENT));
     722             :                         }
     723             : #endif
     724           0 :                         if (BUNappend(lg->dsnapshots, &pos, false) != GDK_SUCCEED)
     725           0 :                                 return GDK_FAIL;
     726             :                 }
     727             :         }
     728             :         return GDK_SUCCEED;
     729             : }
     730             : 
     731             : static log_return
     732           0 : log_read_create(old_logger *lg, trans *tr, char *name, char tpe, oid id)
     733             : {
     734           0 :         char *buf = log_read_string(lg);
     735             :         int ht, tt;
     736             :         char *ha, *ta;
     737             : 
     738           0 :         if (lg->lg->debug & 1)
     739           0 :                 fprintf(stderr, "#log_read_create %s\n", name);
     740             : 
     741           0 :         if (buf == NULL)
     742             :                 return LOG_EOF;
     743           0 :         if (buf == (char *) -1)
     744             :                 return LOG_ERR;
     745             :         ha = buf;
     746           0 :         ta = strchr(buf, ',');
     747           0 :         if (ta == NULL) {
     748           0 :                 TRC_CRITICAL(GDK, "inconsistent data read\n");
     749           0 :                 return LOG_ERR;
     750             :         }
     751           0 :         *ta++ = 0;              /* skip over , */
     752           0 :         if (strcmp(ha, "vid") == 0) {
     753             :                 ht = -1;
     754             :         } else {
     755           0 :                 ht = ATOMindex(ha);
     756             :         }
     757           0 :         if (strcmp(ta, "vid") == 0) {
     758             :                 tt = -1;
     759             :         } else {
     760           0 :                 tt = ATOMindex(ta);
     761             :         }
     762           0 :         GDKfree(buf);
     763           0 :         if (tr_grow(tr) == GDK_SUCCEED) {
     764           0 :                 tr->changes[tr->nr].type = LOG_CREATE;
     765           0 :                 tr->changes[tr->nr].ht = ht;
     766           0 :                 tr->changes[tr->nr].tt = tt;
     767           0 :                 tr->changes[tr->nr].tpe = tpe;
     768           0 :                 tr->changes[tr->nr].cid = id;
     769           0 :                 if ((tr->changes[tr->nr].name = GDKstrdup(name)) == NULL)
     770             :                         return LOG_ERR;
     771           0 :                 tr->changes[tr->nr].b = NULL;
     772           0 :                 tr->nr++;
     773             :         }
     774             : 
     775             :         return LOG_OK;
     776             : }
     777             : 
     778             : static gdk_return
     779           0 : la_bat_create(old_logger *lg, logaction *la)
     780             : {
     781           0 :         int tt = (la->tt < 0) ? TYPE_void : la->tt;
     782             :         BAT *b;
     783             : 
     784             :         /* formerly head column type, should be void */
     785           0 :         assert(((la->ht < 0) ? TYPE_void : la->ht) == TYPE_void);
     786           0 :         if ((b = COLnew(0, tt, BATSIZE, PERSISTENT)) == NULL)
     787             :                 return GDK_FAIL;
     788             : 
     789           0 :         if (la->tt < 0)
     790           0 :                 BATtseqbase(b, 0);
     791             : 
     792           0 :         if ((b = BATsetaccess(b, BAT_READ)) == NULL ||
     793           0 :             logger_add_bat(lg, b, la->name, la->tpe, la->cid) != GDK_SUCCEED) {
     794             :                 logbat_destroy(b);
     795           0 :                 return GDK_FAIL;
     796             :         }
     797             :         logbat_destroy(b);
     798           0 :         return GDK_SUCCEED;
     799             : }
     800             : 
     801             : static log_return
     802           0 : log_read_use(old_logger *lg, trans *tr, logformat *l, char *name, char tpe, oid id)
     803             : {
     804             :         (void) lg;
     805             : 
     806           0 :         if (tr_grow(tr) != GDK_SUCCEED)
     807             :                 return LOG_ERR;
     808           0 :         tr->changes[tr->nr].type = LOG_USE;
     809           0 :         tr->changes[tr->nr].nr = l->nr;
     810           0 :         tr->changes[tr->nr].tpe = tpe;
     811           0 :         tr->changes[tr->nr].cid = id;
     812           0 :         if ((tr->changes[tr->nr].name = GDKstrdup(name)) == NULL)
     813             :                 return LOG_ERR;
     814           0 :         tr->changes[tr->nr].b = NULL;
     815           0 :         tr->nr++;
     816           0 :         return LOG_OK;
     817             : }
     818             : 
     819             : static gdk_return
     820           0 : la_bat_use(old_logger *lg, logaction *la)
     821             : {
     822           0 :         log_bid bid = (log_bid) la->nr;
     823           0 :         BAT *b = BATdescriptor(bid);
     824             :         BUN p;
     825             : 
     826           0 :         assert(la->nr <= (lng) INT_MAX);
     827           0 :         if (b == NULL) {
     828           0 :                 GDKerror("logger: could not use bat (%d) for %s\n", (int) bid, NAME(la->name, la->tpe, la->cid));
     829           0 :                 return GDK_FAIL;
     830             :         }
     831           0 :         if (logger_add_bat(lg, b, la->name, la->tpe, la->cid) != GDK_SUCCEED)
     832           0 :                 goto bailout;
     833             : #ifndef NDEBUG
     834           0 :         assert(b->batRole == PERSISTENT);
     835           0 :         assert(0 <= b->theap->farmid && b->theap->farmid < MAXFARMS);
     836           0 :         assert(BBPfarms[b->theap->farmid].roles & (1 << PERSISTENT));
     837           0 :         if (b->tvheap) {
     838           0 :                 assert(0 <= b->tvheap->farmid && b->tvheap->farmid < MAXFARMS);
     839           0 :                 assert(BBPfarms[b->tvheap->farmid].roles & (1 << PERSISTENT));
     840             :         }
     841             : #endif
     842           0 :         if ((p = log_find(lg->snapshots_bid, lg->dsnapshots, b->batCacheid)) != BUN_NONE &&
     843           0 :             p >= lg->snapshots_bid->batInserted) {
     844           0 :                 assert(lg->snapshots_tid->hseqbase == 0);
     845           0 :                 if (BUNreplace(lg->snapshots_tid, p, &lg->tid, false) != GDK_SUCCEED)
     846           0 :                         goto bailout;
     847             :         } else {
     848           0 :                 if (p != BUN_NONE) {
     849           0 :                         oid pos = p;
     850           0 :                         if (BUNappend(lg->dsnapshots, &pos, false) != GDK_SUCCEED)
     851           0 :                                 goto bailout;
     852             :                 }
     853             :                 /* move to the dirty new part of the snapshots list,
     854             :                  * new snapshots will get flushed to disk */
     855           0 :                 if (BUNappend(lg->snapshots_bid, &b->batCacheid, false) != GDK_SUCCEED ||
     856           0 :                     BUNappend(lg->snapshots_tid, &lg->tid, false) != GDK_SUCCEED)
     857           0 :                         goto bailout;
     858             :         }
     859             :         logbat_destroy(b);
     860           0 :         return GDK_SUCCEED;
     861             : 
     862           0 :   bailout:
     863             :         logbat_destroy(b);
     864           0 :         return GDK_FAIL;
     865             : }
     866             : 
     867             : 
     868             : #define TR_SIZE         1024
     869             : 
     870             : static trans *
     871           0 : tr_create(trans *tr, int tid)
     872             : {
     873           0 :         trans *ntr = GDKmalloc(sizeof(trans));
     874             : 
     875           0 :         if (ntr == NULL)
     876             :                 return NULL;
     877           0 :         ntr->tid = tid;
     878           0 :         ntr->sz = TR_SIZE;
     879           0 :         ntr->nr = 0;
     880           0 :         ntr->changes = GDKmalloc(sizeof(logaction) * TR_SIZE);
     881           0 :         if (ntr->changes == NULL) {
     882           0 :                 GDKfree(ntr);
     883           0 :                 return NULL;
     884             :         }
     885           0 :         ntr->tr = tr;
     886           0 :         return ntr;
     887             : }
     888             : 
     889             : static trans *
     890           0 : tr_find(trans *tr, int tid)
     891             : /* finds the tid and reorders the chain list, puts trans with tid first */
     892             : {
     893             :         trans *t = tr, *p = NULL;
     894             : 
     895           0 :         while (t && t->tid != tid) {
     896             :                 p = t;
     897           0 :                 t = t->tr;
     898             :         }
     899           0 :         if (t == NULL)
     900             :                 return NULL;    /* BAD missing transaction */
     901           0 :         if (t == tr)
     902             :                 return tr;
     903           0 :         if (t->tr)           /* get this tid out of the list */
     904           0 :                 p->tr = t->tr;
     905           0 :         t->tr = tr;          /* and move it to the front */
     906           0 :         return t;
     907             : }
     908             : 
     909             : static gdk_return
     910           0 : la_apply(old_logger *lg, logaction *c)
     911             : {
     912             :         gdk_return ret = GDK_FAIL;
     913             : 
     914           0 :         switch (c->type) {
     915           0 :         case LOG_INSERT:
     916             :         case LOG_UPDATE:
     917           0 :                 ret = la_bat_updates(lg, c);
     918           0 :                 break;
     919           0 :         case LOG_CREATE:
     920           0 :                 ret = la_bat_create(lg, c);
     921           0 :                 break;
     922           0 :         case LOG_USE:
     923           0 :                 ret = la_bat_use(lg, c);
     924           0 :                 break;
     925           0 :         case LOG_DESTROY:
     926           0 :                 ret = la_bat_destroy(lg, c);
     927           0 :                 break;
     928           0 :         case LOG_CLEAR:
     929           0 :                 ret = la_bat_clear(lg, c);
     930           0 :                 break;
     931             :         default:
     932           0 :                 assert(0);
     933             :         }
     934           0 :         lg->changes += (ret == GDK_SUCCEED);
     935           0 :         return ret;
     936             : }
     937             : 
     938             : static void
     939           0 : la_destroy(logaction *c)
     940             : {
     941           0 :         if (c->name)
     942           0 :                 GDKfree(c->name);
     943           0 :         if (c->b)
     944             :                 logbat_destroy(c->b);
     945           0 : }
     946             : 
     947             : static gdk_return
     948           0 : tr_grow(trans *tr)
     949             : {
     950           0 :         if (tr->nr == tr->sz) {
     951             :                 logaction *changes;
     952           0 :                 tr->sz <<= 1;
     953           0 :                 changes = GDKrealloc(tr->changes, tr->sz * sizeof(logaction));
     954           0 :                 if (changes == NULL)
     955             :                         return GDK_FAIL;
     956           0 :                 tr->changes = changes;
     957             :         }
     958             :         /* cleanup the next */
     959           0 :         tr->changes[tr->nr].name = NULL;
     960           0 :         tr->changes[tr->nr].b = NULL;
     961           0 :         return GDK_SUCCEED;
     962             : }
     963             : 
     964             : static trans *
     965           0 : tr_destroy(trans *tr)
     966             : {
     967           0 :         trans *r = tr->tr;
     968             : 
     969           0 :         GDKfree(tr->changes);
     970           0 :         GDKfree(tr);
     971           0 :         return r;
     972             : }
     973             : 
     974             : static trans *
     975           0 : tr_abort(old_logger *lg, trans *tr)
     976             : {
     977             :         int i;
     978             : 
     979           0 :         if (lg->lg->debug & 1)
     980           0 :                 fprintf(stderr, "#tr_abort\n");
     981             : 
     982           0 :         for (i = 0; i < tr->nr; i++)
     983           0 :                 la_destroy(&tr->changes[i]);
     984           0 :         return tr_destroy(tr);
     985             : }
     986             : 
     987             : static trans *
     988           0 : tr_commit(old_logger *lg, trans *tr)
     989             : {
     990             :         int i;
     991             : 
     992           0 :         if (lg->lg->debug & 1)
     993           0 :                 fprintf(stderr, "#tr_commit\n");
     994             : 
     995           0 :         for (i = 0; i < tr->nr; i++) {
     996           0 :                 if (la_apply(lg, &tr->changes[i]) != GDK_SUCCEED) {
     997             :                         do {
     998           0 :                                 tr = tr_abort(lg, tr);
     999           0 :                         } while (tr != NULL);
    1000             :                         return (trans *) -1;
    1001             :                 }
    1002           0 :                 la_destroy(&tr->changes[i]);
    1003             :         }
    1004           0 :         return tr_destroy(tr);
    1005             : }
    1006             : 
    1007             : static inline void
    1008          31 : logger_close(old_logger *lg)
    1009             : {
    1010          31 :         if (!LOG_DISABLED(lg))
    1011          31 :                 close_stream(lg->log);
    1012          31 :         lg->log = NULL;
    1013          31 : }
    1014             : 
    1015             : static gdk_return
    1016          31 : logger_readlog(old_logger *lg, char *filename, bool *filemissing)
    1017             : {
    1018             :         trans *tr = NULL;
    1019             :         logformat l;
    1020             :         log_return err = LOG_OK;
    1021             :         time_t t0, t1;
    1022             :         struct stat sb;
    1023          31 :         int dbg = GDKdebug;
    1024             :         int fd;
    1025             : 
    1026          31 :         GDKdebug &= ~(CHECKMASK|PROPMASK);
    1027             : 
    1028          31 :         if (lg->lg->debug & 1) {
    1029           0 :                 fprintf(stderr, "#logger_readlog opening %s\n", filename);
    1030             :         }
    1031             : 
    1032          31 :         lg->log = open_rstream(filename);
    1033             : 
    1034             :         /* if the file doesn't exist, there is nothing to be read back */
    1035          31 :         if (lg->log == NULL || mnstr_errnr(lg->log)) {
    1036           8 :                 logger_close(lg);
    1037           8 :                 GDKdebug = dbg;
    1038           8 :                 *filemissing = true;
    1039           8 :                 return GDK_SUCCEED;
    1040             :         }
    1041             :         short byteorder;
    1042          23 :         switch (mnstr_read(lg->log, &byteorder, sizeof(byteorder), 1)) {
    1043           0 :         case -1:
    1044           0 :                 logger_close(lg);
    1045           0 :                 GDKdebug = dbg;
    1046           0 :                 return GDK_FAIL;
    1047           0 :         case 0:
    1048             :                 /* empty file is ok */
    1049           0 :                 logger_close(lg);
    1050           0 :                 GDKdebug = dbg;
    1051           0 :                 return GDK_SUCCEED;
    1052          23 :         case 1:
    1053             :                 /* if not empty, must start with correct byte order mark */
    1054          23 :                 if (byteorder != 1234) {
    1055           0 :                         TRC_CRITICAL(GDK, "incorrect byte order word in file %s\n", filename);
    1056           0 :                         logger_close(lg);
    1057           0 :                         GDKdebug = dbg;
    1058           0 :                         return GDK_FAIL;
    1059             :                 }
    1060             :                 break;
    1061             :         }
    1062          46 :         if ((fd = getFileNo(lg->log)) < 0 || fstat(fd, &sb) < 0) {
    1063           0 :                 TRC_CRITICAL(GDK, "fstat on opened file %s failed\n", filename);
    1064           0 :                 logger_close(lg);
    1065           0 :                 GDKdebug = dbg;
    1066             :                 /* If the file could be opened, but fstat fails,
    1067             :                  * something weird is going on */
    1068           0 :                 return GDK_FAIL;
    1069             :         }
    1070          23 :         t0 = time(NULL);
    1071          23 :         if (lg->lg->debug & 1) {
    1072           0 :                 printf("# Start reading the write-ahead log '%s'\n", filename);
    1073           0 :                 fflush(stdout);
    1074             :         }
    1075          23 :         while (err == LOG_OK && log_read_format(lg, &l)) {
    1076             :                 char *name = NULL;
    1077             :                 char tpe;
    1078             :                 oid id;
    1079             : 
    1080           0 :                 t1 = time(NULL);
    1081           0 :                 if (t1 - t0 > 10) {
    1082             :                         lng fpos;
    1083             :                         t0 = t1;
    1084             :                         /* not more than once every 10 seconds */
    1085           0 :                         fpos = (lng) getfilepos(getFile(lg->log));
    1086           0 :                         if (fpos >= 0) {
    1087           0 :                                 printf("# still reading write-ahead log \"%s\" (%d%% done)\n", filename, (int) ((fpos * 100 + 50) / sb.st_size));
    1088           0 :                                 fflush(stdout);
    1089             :                         }
    1090             :                 }
    1091           0 :                 if ((l.flag >= LOG_INSERT && l.flag <= LOG_CLEAR) || l.flag == LOG_CREATE_ID || l.flag == LOG_USE_ID) {
    1092           0 :                         name = log_read_string(lg);
    1093             : 
    1094           0 :                         if (name == NULL) {
    1095             :                                 err = LOG_EOF;
    1096           0 :                                 break;
    1097             :                         }
    1098           0 :                         if (name == (char *) -1) {
    1099             :                                 err = LOG_ERR;
    1100             :                                 break;
    1101             :                         }
    1102             :                 }
    1103           0 :                 if (lg->lg->debug & 1) {
    1104           0 :                         fprintf(stderr, "#logger_readlog: ");
    1105           0 :                         if (l.flag > 0 &&
    1106             :                             l.flag < (char) (sizeof(log_commands) / sizeof(log_commands[0])))
    1107           0 :                                 fprintf(stderr, "%s", log_commands[(int) l.flag]);
    1108             :                         else
    1109           0 :                                 fprintf(stderr, "%d", l.flag);
    1110           0 :                         fprintf(stderr, " %d " LLFMT, l.tid, l.nr);
    1111           0 :                         if (name)
    1112           0 :                                 fprintf(stderr, " %s", name);
    1113           0 :                         fprintf(stderr, "\n");
    1114             :                 }
    1115             :                 /* find proper transaction record */
    1116           0 :                 if (l.flag != LOG_START)
    1117           0 :                         tr = tr_find(tr, l.tid);
    1118             :                 /* the functions we call here can succeed (LOG_OK),
    1119             :                  * but they can also fail for two different reasons:
    1120             :                  * they can run out of input (LOG_EOF -- this is not
    1121             :                  * serious, we just abort the remaining transactions),
    1122             :                  * or some malloc or BAT update fails (LOG_ERR -- this
    1123             :                  * is serious, we must abort the complete process);
    1124             :                  * the latter failure causes the current function to
    1125             :                  * return GDK_FAIL */
    1126           0 :                 switch (l.flag) {
    1127           0 :                 case LOG_START:
    1128           0 :                         assert(l.nr <= (lng) INT_MAX);
    1129           0 :                         if (l.nr > lg->tid)
    1130           0 :                                 lg->tid = (int)l.nr;
    1131           0 :                         if ((tr = tr_create(tr, (int)l.nr)) == NULL) {
    1132             :                                 err = LOG_ERR;
    1133             :                                 break;
    1134             :                         }
    1135           0 :                         if (lg->lg->debug & 1)
    1136           0 :                                 fprintf(stderr, "#logger tstart %d\n", tr->tid);
    1137             :                         break;
    1138           0 :                 case LOG_END:
    1139           0 :                         if (tr == NULL)
    1140             :                                 err = LOG_EOF;
    1141           0 :                         else if (l.tid != l.nr) /* abort record */
    1142           0 :                                 tr = tr_abort(lg, tr);
    1143             :                         else
    1144           0 :                                 tr = tr_commit(lg, tr);
    1145             :                         break;
    1146           0 :                 case LOG_SEQ:
    1147           0 :                         err = log_read_seq(lg, &l);
    1148           0 :                         break;
    1149           0 :                 case LOG_INSERT:
    1150             :                 case LOG_UPDATE:
    1151           0 :                         if (name == NULL || tr == NULL)
    1152             :                                 err = LOG_EOF;
    1153             :                         else
    1154           0 :                                 err = log_read_updates(lg, tr, &l, name, 0, 0, 0);
    1155             :                         break;
    1156           0 :                 case LOG_INSERT_ID:
    1157             :                 case LOG_UPDATE_ID:
    1158             :                 case LOG_UPDATE_PAX: {
    1159           0 :                         int pax = (l.flag == LOG_UPDATE_PAX);
    1160           0 :                         l.flag = (l.flag == LOG_INSERT_ID)?LOG_INSERT:LOG_UPDATE;
    1161           0 :                         if (log_read_id(lg, &tpe, &id) != LOG_OK)
    1162             :                                 err = LOG_ERR;
    1163             :                         else
    1164           0 :                                 err = log_read_updates(lg, tr, &l, name, tpe, id, pax);
    1165             :                 }       break;
    1166           0 :                 case LOG_CREATE:
    1167           0 :                         if (name == NULL || tr == NULL)
    1168             :                                 err = LOG_EOF;
    1169             :                         else
    1170           0 :                                 err = log_read_create(lg, tr, name, 0, 0);
    1171             :                         break;
    1172           0 :                 case LOG_CREATE_ID:
    1173           0 :                         l.flag = LOG_CREATE;
    1174           0 :                         if (tr == NULL || log_read_id(lg, &tpe, &id) != LOG_OK)
    1175             :                                 err = LOG_EOF;
    1176             :                         else
    1177           0 :                                 err = log_read_create(lg, tr, name, tpe, id);
    1178             :                         break;
    1179           0 :                 case LOG_USE:
    1180           0 :                         if (name == NULL || tr == NULL)
    1181             :                                 err = LOG_EOF;
    1182             :                         else
    1183           0 :                                 err = log_read_use(lg, tr, &l, name, 0, 0);
    1184             :                         break;
    1185           0 :                 case LOG_USE_ID:
    1186           0 :                         l.flag = LOG_USE;
    1187           0 :                         if (tr == NULL || log_read_id(lg, &tpe, &id) != LOG_OK)
    1188             :                                 err = LOG_EOF;
    1189             :                         else
    1190           0 :                                 err = log_read_use(lg, tr, &l, name, tpe, id);
    1191             :                         break;
    1192           0 :                 case LOG_DESTROY:
    1193           0 :                         if (name == NULL || tr == NULL)
    1194             :                                 err = LOG_EOF;
    1195             :                         else
    1196           0 :                                 err = log_read_destroy(lg, tr, name, 0, 0);
    1197             :                         break;
    1198           0 :                 case LOG_DESTROY_ID:
    1199           0 :                         l.flag = LOG_DESTROY;
    1200           0 :                         if (tr == NULL || log_read_id(lg, &tpe, &id) != LOG_OK)
    1201             :                                 err = LOG_EOF;
    1202             :                         else
    1203           0 :                                 err = log_read_destroy(lg, tr, name, tpe, id);
    1204             :                         break;
    1205           0 :                 case LOG_CLEAR:
    1206           0 :                         if (name == NULL || tr == NULL)
    1207             :                                 err = LOG_EOF;
    1208             :                         else
    1209           0 :                                 err = log_read_clear(lg, tr, name, 0, 0);
    1210             :                         break;
    1211           0 :                 case LOG_CLEAR_ID:
    1212           0 :                         l.flag = LOG_CLEAR;
    1213           0 :                         if (tr == NULL || log_read_id(lg, &tpe, &id) != LOG_OK)
    1214             :                                 err = LOG_EOF;
    1215             :                         else
    1216           0 :                                 err = log_read_clear(lg, tr, name, tpe, id);
    1217             :                         break;
    1218             :                 case 0:
    1219             :                         break;
    1220           0 :                 default:
    1221             :                         err = LOG_ERR;
    1222             :                 }
    1223           0 :                 if (name)
    1224           0 :                         GDKfree(name);
    1225           0 :                 if (tr == (trans *) -1) {
    1226             :                         err = LOG_ERR;
    1227             :                         tr = NULL;
    1228             :                         break;
    1229             :                 }
    1230             :         }
    1231          23 :         logger_close(lg);
    1232             : 
    1233             :         /* remaining transactions are not committed, ie abort */
    1234          23 :         while (tr)
    1235           0 :                 tr = tr_abort(lg, tr);
    1236          23 :         if (lg->lg->debug & 1) {
    1237           0 :                 printf("# Finished reading the write-ahead log '%s'\n", filename);
    1238           0 :                 fflush(stdout);
    1239             :         }
    1240          23 :         GDKdebug = dbg;
    1241             :         /* we cannot distinguish errors from incomplete transactions
    1242             :          * (even if we would log aborts in the logs). So we simply
    1243             :          * abort and move to the next log file */
    1244          23 :         return err == LOG_ERR ? GDK_FAIL : GDK_SUCCEED;
    1245             : }
    1246             : 
    1247             : /*
    1248             :  * The log files are incrementally numbered, starting from 2. They are
    1249             :  * processed in the same sequence.
    1250             :  */
    1251             : static gdk_return
    1252           8 : logger_readlogs(old_logger *lg, FILE *fp, char *filename)
    1253             : {
    1254             :         gdk_return res = GDK_SUCCEED;
    1255             :         char id[BUFSIZ];
    1256             : 
    1257           8 :         if (lg->lg->debug & 1) {
    1258           0 :                 fprintf(stderr, "#logger_readlogs logger id is " LLFMT "\n", lg->id);
    1259             :         }
    1260             : 
    1261           8 :         if (fgets(id, sizeof(id), fp) != NULL) {
    1262             :                 char log_filename[FILENAME_MAX];
    1263           8 :                 lng lid = strtoll(id, NULL, 10);
    1264             : 
    1265           8 :                 if (lg->lg->debug & 1) {
    1266           0 :                         fprintf(stderr, "#logger_readlogs last logger id written in %s is " LLFMT "\n", filename, lid);
    1267             :                 }
    1268             : 
    1269           8 :                 if (lid >= lg->id) {
    1270           8 :                         bool filemissing = false;
    1271             : 
    1272           8 :                         lg->id = lid;
    1273          39 :                         while (res == GDK_SUCCEED && !filemissing) {
    1274          31 :                                 if (snprintf(log_filename, sizeof(log_filename), "%s." LLFMT, filename, lg->id) >= FILENAME_MAX) {
    1275           0 :                                         GDKerror("Logger filename path is too large\n");
    1276           0 :                                         return GDK_FAIL;
    1277             :                                 }
    1278          31 :                                 res = logger_readlog(lg, log_filename, &filemissing);
    1279          31 :                                 if (!filemissing)
    1280          23 :                                         lg->id++;
    1281             :                         }
    1282             :                 } else {
    1283             :                         bool filemissing = false;
    1284             :                         while (lid >= lg->id && res == GDK_SUCCEED) {
    1285             :                                 if (snprintf(log_filename, sizeof(log_filename), "%s." LLFMT, filename, lg->id) >= FILENAME_MAX) {
    1286             :                                         GDKerror("Logger filename path is too large\n");
    1287             :                                         return GDK_FAIL;
    1288             :                                 }
    1289             :                                 res = logger_readlog(lg, log_filename, &filemissing);
    1290             :                                 /* Increment the id only at the end,
    1291             :                                  * since we want to re-read the last
    1292             :                                  * file.  That is because last time we
    1293             :                                  * read it, it was empty, since the
    1294             :                                  * logger creates empty files and
    1295             :                                  * fills them in later. */
    1296             :                                 lg->id++;
    1297             :                         }
    1298             :                         if (lid < lg->id) {
    1299           0 :                                 lg->id = lid;
    1300             :                         }
    1301             :                 }
    1302             :         }
    1303             :         return res;
    1304             : }
    1305             : 
    1306             : static gdk_return
    1307           8 : check_version(old_logger *lg, FILE *fp, int version)
    1308             : {
    1309             :         /* if these were equal we wouldn't have gotten here */
    1310           8 :         assert(version != lg->lg->version);
    1311             : 
    1312          16 :         if (lg->lg->prefuncp == NULL ||
    1313           8 :             (*lg->lg->prefuncp)(lg->lg->funcdata, version, lg->lg->version) != GDK_SUCCEED) {
    1314           0 :                 GDKerror("Incompatible database version %06d, "
    1315             :                          "this server supports version %06d.\n%s",
    1316             :                          version, lg->lg->version,
    1317             :                          version < lg->lg->version ? "Maybe you need to upgrade to an intermediate release first.\n" : "");
    1318           0 :                 return GDK_FAIL;
    1319             :         }
    1320             : 
    1321          16 :         if (fgetc(fp) != '\n' ||         /* skip \n */
    1322           8 :             fgetc(fp) != '\n') {         /* skip \n */
    1323           0 :                 GDKerror("Badly formatted log file");
    1324           0 :                 return GDK_FAIL;
    1325             :         }
    1326             :         return GDK_SUCCEED;
    1327             : }
    1328             : 
    1329             : /* Load data from the logger logdir
    1330             :  * Initialize new directories and catalog files if none are present,
    1331             :  * unless running in read-only mode
    1332             :  * Load data and persist it in the BATs */
    1333             : static gdk_return
    1334           8 : logger_load(const char *fn, char filename[FILENAME_MAX], old_logger *lg, FILE *fp, int version)
    1335             : {
    1336             :         size_t len;
    1337             :         char bak[FILENAME_MAX];
    1338             :         str filenamestr = NULL;
    1339           8 :         log_bid snapshots_bid = 0;
    1340             :         bat catalog_bid, catalog_nme, catalog_tpe, catalog_oid, dcatalog;
    1341           8 :         int dbg = GDKdebug;
    1342             : 
    1343           8 :         assert(!LOG_DISABLED(lg));
    1344             : 
    1345           8 :         if ((filenamestr = GDKfilepath(0, lg->lg->dir, LOGFILE, NULL)) == NULL)
    1346           0 :                 goto error;
    1347           8 :         len = strcpy_len(filename, filenamestr, FILENAME_MAX);
    1348           8 :         GDKfree(filenamestr);
    1349           8 :         if (len >= FILENAME_MAX) {
    1350           0 :                 GDKerror("Logger filename path is too large\n");
    1351           0 :                 goto error;
    1352             :         }
    1353             : 
    1354           8 :         strconcat_len(bak, sizeof(bak), fn, "_catalog_bid", NULL);
    1355           8 :         catalog_bid = BBPindex(bak);
    1356             : 
    1357           8 :         assert(catalog_bid != 0); /* has been checked by new logger */
    1358             : 
    1359             :         /* find the persistent catalog. As non persistent bats
    1360             :          * require a logical reference we also add a logical
    1361             :          * reference for the persistent bats */
    1362             :         size_t i;
    1363             :         BUN p, q;
    1364             :         BAT *b, *n, *t, *o, *d;
    1365             : 
    1366           8 :         b = BATdescriptor(catalog_bid);
    1367           8 :         if (b == NULL) {
    1368           0 :                 GDKerror("inconsistent database, catalog does not exist");
    1369           0 :                 goto error;
    1370             :         }
    1371             : 
    1372           8 :         strconcat_len(bak, sizeof(bak), fn, "_catalog_nme", NULL);
    1373           8 :         catalog_nme = BBPindex(bak);
    1374           8 :         n = BATdescriptor(catalog_nme);
    1375           8 :         if (n == NULL) {
    1376           0 :                 BBPunfix(b->batCacheid);
    1377           0 :                 GDKerror("inconsistent database, catalog_nme does not exist");
    1378           0 :                 goto error;
    1379             :         }
    1380             : 
    1381           8 :         strconcat_len(bak, sizeof(bak), fn, "_catalog_tpe", NULL);
    1382           8 :         catalog_tpe = BBPindex(bak);
    1383           8 :         t = BATdescriptor(catalog_tpe);
    1384           8 :         if (t == NULL) {
    1385           0 :                 t = logbat_new(TYPE_bte, BATSIZE, TRANSIENT);
    1386           0 :                 if (t == NULL
    1387           0 :                     ||BBPrename(t->batCacheid, bak) < 0) {
    1388           0 :                         BBPunfix(b->batCacheid);
    1389           0 :                         BBPunfix(n->batCacheid);
    1390           0 :                         if (t)
    1391           0 :                                 BBPunfix(t->batCacheid);
    1392           0 :                         GDKerror("inconsistent database, catalog_tpe does not exist");
    1393           0 :                         goto error;
    1394             :                 }
    1395           0 :                 for(i=0;i<BATcount(n); i++) {
    1396           0 :                         char zero = 0;
    1397           0 :                         if (BUNappend(t, &zero, false) != GDK_SUCCEED)
    1398           0 :                                 goto error;
    1399             :                 }
    1400           0 :                 lg->with_ids = false;
    1401             :         } else {
    1402           8 :                 if (BUNappend(lg->del, &t->batCacheid, false) != GDK_SUCCEED)
    1403           0 :                         goto error;
    1404           8 :                 BBPretain(t->batCacheid);
    1405             :         }
    1406             : 
    1407           8 :         strconcat_len(bak, sizeof(bak), fn, "_catalog_oid", NULL);
    1408           8 :         catalog_oid = BBPindex(bak);
    1409           8 :         o = BATdescriptor(catalog_oid);
    1410           8 :         if (o == NULL) {
    1411           0 :                 o = logbat_new(TYPE_lng, BATSIZE, TRANSIENT);
    1412           0 :                 if (o == NULL
    1413           0 :                     ||BBPrename(o->batCacheid, bak) < 0) {
    1414           0 :                         BBPunfix(b->batCacheid);
    1415           0 :                         BBPunfix(n->batCacheid);
    1416           0 :                         BBPunfix(t->batCacheid);
    1417           0 :                         if (o)
    1418           0 :                                 BBPunfix(o->batCacheid);
    1419           0 :                         GDKerror("inconsistent database, catalog_oid does not exist");
    1420           0 :                         goto error;
    1421             :                 }
    1422           0 :                 for(i=0;i<BATcount(n); i++) {
    1423           0 :                         lng zero = 0;
    1424           0 :                         if (BUNappend(o, &zero, false) != GDK_SUCCEED)
    1425           0 :                                 goto error;
    1426             :                 }
    1427           0 :                 lg->with_ids = false;
    1428             :         } else {
    1429           8 :                 if (BUNappend(lg->del, &o->batCacheid, false) != GDK_SUCCEED)
    1430           0 :                         goto error;
    1431           8 :                 BBPretain(o->batCacheid);
    1432             :         }
    1433             : 
    1434           8 :         strconcat_len(bak, sizeof(bak), fn, "_dcatalog", NULL);
    1435           8 :         dcatalog = BBPindex(bak);
    1436           8 :         d = BATdescriptor(dcatalog);
    1437           8 :         if (d == NULL) {
    1438             :                 /* older database: create dcatalog and convert
    1439             :                  * catalog_bid and catalog_nme to
    1440             :                  * dense-headed */
    1441           0 :                 d = logbat_new(TYPE_oid, BATSIZE, TRANSIENT);
    1442           0 :                 if (d == NULL) {
    1443           0 :                         GDKerror("Logger_new: cannot create dcatalog bat");
    1444           0 :                         BBPunfix(b->batCacheid);
    1445           0 :                         BBPunfix(n->batCacheid);
    1446           0 :                         BBPunfix(t->batCacheid);
    1447           0 :                         BBPunfix(o->batCacheid);
    1448           0 :                         goto error;
    1449             :                 }
    1450           0 :                 if (BBPrename(d->batCacheid, bak) < 0) {
    1451           0 :                         BBPunfix(b->batCacheid);
    1452           0 :                         BBPunfix(n->batCacheid);
    1453           0 :                         BBPunfix(t->batCacheid);
    1454           0 :                         BBPunfix(o->batCacheid);
    1455           0 :                         goto error;
    1456             :                 }
    1457             :         } else {
    1458           8 :                 if (BUNappend(lg->del, &d->batCacheid, false) != GDK_SUCCEED)
    1459           0 :                         goto error;
    1460           8 :                 BBPretain(d->batCacheid);
    1461             :         }
    1462             : 
    1463           8 :         lg->catalog_bid = b;
    1464           8 :         lg->catalog_nme = n;
    1465           8 :         lg->catalog_tpe = t;
    1466           8 :         lg->catalog_oid = o;
    1467           8 :         lg->dcatalog = d;
    1468           8 :         if (BUNappend(lg->del, &b->batCacheid, false) != GDK_SUCCEED)
    1469           0 :                 goto error;
    1470           8 :         BBPretain(b->batCacheid);
    1471           8 :         if (BUNappend(lg->del, &n->batCacheid, false) != GDK_SUCCEED)
    1472           0 :                 goto error;
    1473           8 :         BBPretain(n->batCacheid);
    1474             : 
    1475             :         const log_bid *bids;
    1476           8 :         bids = (const log_bid *) Tloc(b, 0);
    1477        3472 :         BATloop(b, p, q) {
    1478        3464 :                 bat bid = bids[p];
    1479        3464 :                 oid pos = p;
    1480             : 
    1481        5787 :                 if (BUNfnd(lg->dcatalog, &pos) == BUN_NONE &&
    1482        2323 :                     BBPretain(bid) == 0 &&
    1483           0 :                     BUNappend(lg->dcatalog, &pos, false) != GDK_SUCCEED)
    1484           0 :                         goto error;
    1485             :         }
    1486             : 
    1487           8 :         lg->freed = logbat_new(TYPE_int, 1, TRANSIENT);
    1488           8 :         if (lg->freed == NULL) {
    1489           0 :                 GDKerror("Logger_new: failed to create freed bat");
    1490           0 :                 goto error;
    1491             :         }
    1492           8 :         snapshots_bid = old_logger_find_bat(lg, "snapshots_bid", 0, 0);
    1493           8 :         if (snapshots_bid == 0) {
    1494           0 :                 lg->snapshots_bid = logbat_new(TYPE_int, 1, TRANSIENT);
    1495           0 :                 lg->snapshots_tid = logbat_new(TYPE_int, 1, TRANSIENT);
    1496           0 :                 lg->dsnapshots = logbat_new(TYPE_oid, 1, TRANSIENT);
    1497           0 :                 if (lg->snapshots_bid == NULL ||
    1498           0 :                     lg->snapshots_tid == NULL ||
    1499             :                     lg->dsnapshots == NULL) {
    1500           0 :                         GDKerror("Logger_new: failed to create snapshots bats");
    1501           0 :                         goto error;
    1502             :                 }
    1503             :         } else {
    1504           8 :                 bat snapshots_tid = old_logger_find_bat(lg, "snapshots_tid", 0, 0);
    1505           8 :                 bat dsnapshots = old_logger_find_bat(lg, "dsnapshots", 0, 0);
    1506             : 
    1507           8 :                 GDKdebug &= ~CHECKMASK;
    1508           8 :                 lg->snapshots_bid = BATdescriptor(snapshots_bid);
    1509           8 :                 if (lg->snapshots_bid == NULL) {
    1510           0 :                         GDKerror("inconsistent database, snapshots_bid does not exist");
    1511           0 :                         goto error;
    1512             :                 }
    1513           8 :                 lg->snapshots_tid = BATdescriptor(snapshots_tid);
    1514           8 :                 if (lg->snapshots_tid == NULL) {
    1515           0 :                         GDKerror("inconsistent database, snapshots_tid does not exist");
    1516           0 :                         goto error;
    1517             :                 }
    1518           8 :                 GDKdebug = dbg;
    1519             : 
    1520           8 :                 if (dsnapshots) {
    1521           8 :                         lg->dsnapshots = BATdescriptor(dsnapshots);
    1522           8 :                         if (lg->dsnapshots == NULL) {
    1523           0 :                                 GDKerror("Logger_new: inconsistent database, snapshots_tid does not exist");
    1524           0 :                                 goto error;
    1525             :                         }
    1526           8 :                         if (BUNappend(lg->del, &dsnapshots, false) != GDK_SUCCEED)
    1527           0 :                                 goto error;
    1528           8 :                         BBPretain(dsnapshots);
    1529             :                 } else {
    1530           0 :                         lg->dsnapshots = logbat_new(TYPE_oid, 1, TRANSIENT);
    1531           0 :                         if (lg->dsnapshots == NULL) {
    1532           0 :                                 GDKerror("Logger_new: cannot create dsnapshot bat");
    1533           0 :                                 goto error;
    1534             :                         }
    1535             :                 }
    1536           8 :                 if (BUNappend(lg->del, &snapshots_bid, false) != GDK_SUCCEED)
    1537           0 :                         goto error;
    1538           8 :                 BBPretain(snapshots_bid);
    1539           8 :                 if (BUNappend(lg->del, &snapshots_tid, false) != GDK_SUCCEED)
    1540           0 :                         goto error;
    1541           8 :                 BBPretain(snapshots_tid);
    1542             :         }
    1543           8 :         strconcat_len(bak, sizeof(bak), fn, "_seqs_id", NULL);
    1544           8 :         if (BBPindex(bak)) {
    1545           8 :                 lg->seqs_id = BATdescriptor(BBPindex(bak));
    1546           8 :                 strconcat_len(bak, sizeof(bak), fn, "_seqs_val", NULL);
    1547           8 :                 lg->seqs_val = BATdescriptor(BBPindex(bak));
    1548           8 :                 strconcat_len(bak, sizeof(bak), fn, "_dseqs", NULL);
    1549           8 :                 lg->dseqs = BATdescriptor(BBPindex(bak));
    1550             :         } else {
    1551           0 :                 lg->seqs_id = logbat_new(TYPE_int, 1, PERSISTENT);
    1552           0 :                 lg->seqs_val = logbat_new(TYPE_lng, 1, PERSISTENT);
    1553           0 :                 lg->dseqs = logbat_new(TYPE_oid, 1, PERSISTENT);
    1554           0 :                 if (lg->seqs_id == NULL ||
    1555           0 :                     lg->seqs_val == NULL ||
    1556             :                     lg->dseqs == NULL) {
    1557           0 :                         GDKerror("Logger_new: cannot create seqs bats");
    1558           0 :                         goto error;
    1559             :                 }
    1560             : 
    1561           0 :                 strconcat_len(bak, sizeof(bak), fn, "_seqs_id", NULL);
    1562           0 :                 if (BBPrename(lg->seqs_id->batCacheid, bak) < 0) {
    1563           0 :                         goto error;
    1564             :                 }
    1565             : 
    1566           0 :                 strconcat_len(bak, sizeof(bak), fn, "_seqs_val", NULL);
    1567           0 :                 if (BBPrename(lg->seqs_val->batCacheid, bak) < 0) {
    1568           0 :                         goto error;
    1569             :                 }
    1570             : 
    1571           0 :                 strconcat_len(bak, sizeof(bak), fn, "_dseqs", NULL);
    1572           0 :                 if (BBPrename(lg->dseqs->batCacheid, bak) < 0) {
    1573           0 :                         goto error;
    1574             :                 }
    1575           0 :                 if (BUNappend(lg->add, &lg->seqs_id->batCacheid, false) != GDK_SUCCEED)
    1576           0 :                         goto error;
    1577           0 :                 BBPretain(lg->seqs_id->batCacheid);
    1578           0 :                 if (BUNappend(lg->add, &lg->seqs_val->batCacheid, false) != GDK_SUCCEED)
    1579           0 :                         goto error;
    1580           0 :                 BBPretain(lg->seqs_val->batCacheid);
    1581           0 :                 if (BUNappend(lg->add, &lg->dseqs->batCacheid, false) != GDK_SUCCEED)
    1582           0 :                         goto error;
    1583           0 :                 BBPretain(lg->dseqs->batCacheid);
    1584             :         }
    1585             : 
    1586           8 :         if (check_version(lg, fp, version) != GDK_SUCCEED) {
    1587           0 :                 goto error;
    1588             :         }
    1589             : 
    1590           8 :         if (logger_readlogs(lg, fp, filename) != GDK_SUCCEED) {
    1591           0 :                 goto error;
    1592             :         }
    1593           8 :         fclose(fp);
    1594             :         fp = NULL;
    1595             : 
    1596          16 :         if (lg->lg->postfuncp &&
    1597           8 :             (*lg->lg->postfuncp)(lg->lg->funcdata, lg) != GDK_SUCCEED)
    1598           0 :                 goto error;
    1599           8 :         lg->lg->postfuncp = NULL; /* not again */
    1600             : 
    1601           8 :         if (BUNappend(lg->add, &lg->lg->catalog_bid->batCacheid, false) != GDK_SUCCEED)
    1602           0 :                 goto error;
    1603           8 :         BBPretain(lg->lg->catalog_bid->batCacheid);
    1604           8 :         if (BUNappend(lg->add, &lg->lg->catalog_id->batCacheid, false) != GDK_SUCCEED)
    1605           0 :                 goto error;
    1606           8 :         BBPretain(lg->lg->catalog_id->batCacheid);
    1607           8 :         if (BUNappend(lg->add, &lg->lg->dcatalog->batCacheid, false) != GDK_SUCCEED)
    1608           0 :                 goto error;
    1609           8 :         BBPretain(lg->lg->dcatalog->batCacheid);
    1610             : 
    1611             :         /* done reading the log, revert to "normal" behavior */
    1612           8 :         geomisoldversion = false;
    1613             : 
    1614           8 :         return GDK_SUCCEED;
    1615           0 :   error:
    1616           0 :         if (fp)
    1617           0 :                 fclose(fp);
    1618           0 :         logbat_destroy(lg->catalog_bid);
    1619           0 :         logbat_destroy(lg->catalog_nme);
    1620           0 :         logbat_destroy(lg->catalog_tpe);
    1621           0 :         logbat_destroy(lg->catalog_oid);
    1622           0 :         logbat_destroy(lg->dcatalog);
    1623           0 :         logbat_destroy(lg->snapshots_bid);
    1624           0 :         logbat_destroy(lg->snapshots_tid);
    1625           0 :         logbat_destroy(lg->dsnapshots);
    1626           0 :         logbat_destroy(lg->freed);
    1627           0 :         logbat_destroy(lg->seqs_id);
    1628           0 :         logbat_destroy(lg->seqs_val);
    1629           0 :         logbat_destroy(lg->dseqs);
    1630           0 :         bids = (const log_bid *) Tloc(lg->add, 0);
    1631           0 :         BATloop(lg->add, p, q) {
    1632           0 :                 BBPrelease(bids[p]);
    1633             :         }
    1634           0 :         logbat_destroy(lg->add);
    1635           0 :         bids = (const log_bid *) Tloc(lg->del, 0);
    1636           0 :         BATloop(lg->del, p, q) {
    1637           0 :                 BBPrelease(bids[p]);
    1638             :         }
    1639           0 :         logbat_destroy(lg->del);
    1640           0 :         GDKfree(lg->local_dir);
    1641           0 :         GDKfree(lg);
    1642           0 :         return GDK_FAIL;
    1643             : }
    1644             : 
    1645             : /* Initialize a new logger
    1646             :  * It will load any data in the logdir and persist it in the BATs*/
    1647             : static old_logger *
    1648           8 : logger_new(logger *lg, const char *fn, const char *logdir, FILE *fp, int version, const char *logfile)
    1649             : {
    1650             :         old_logger *old_lg;
    1651             :         char filename[FILENAME_MAX];
    1652             : 
    1653           8 :         assert(!GDKinmemory(0));
    1654           8 :         assert(lg != NULL);
    1655           8 :         if (GDKinmemory(0)) {
    1656           0 :                 TRC_CRITICAL(GDK, "old logger can only be used with a disk-based database\n");
    1657           0 :                 fclose(fp);
    1658           0 :                 return NULL;
    1659             :         }
    1660           8 :         if (MT_path_absolute(logdir)) {
    1661           0 :                 TRC_CRITICAL(GDK, "logdir must be relative path\n");
    1662           0 :                 fclose(fp);
    1663           0 :                 return NULL;
    1664             :         }
    1665             : 
    1666           8 :         old_lg = GDKmalloc(sizeof(struct old_logger));
    1667           8 :         if (old_lg == NULL) {
    1668           0 :                 TRC_CRITICAL(GDK, "allocating logger structure failed\n");
    1669           0 :                 fclose(fp);
    1670           0 :                 return NULL;
    1671             :         }
    1672             : 
    1673           8 :         *old_lg = (struct old_logger) {
    1674             :                 .lg = lg,
    1675             :                 .filename = logfile,
    1676             :                 .with_ids = true,
    1677             :                 .id = 1,
    1678             :         };
    1679             : 
    1680           8 :         old_lg->add = COLnew(0, TYPE_int, 0, TRANSIENT);
    1681           8 :         old_lg->del = COLnew(0, TYPE_int, 0, TRANSIENT);
    1682           8 :         if (old_lg->add == NULL || old_lg->del == NULL) {
    1683           0 :                 TRC_CRITICAL(GDK, "cannot allocate temporary bats\n");
    1684           0 :                 goto bailout;
    1685             :         }
    1686             : 
    1687           8 :         if (snprintf(filename, sizeof(filename), "%s%c%s%c", logdir, DIR_SEP, fn, DIR_SEP) >= FILENAME_MAX) {
    1688           0 :                 TRC_CRITICAL(GDK, "filename is too large\n");
    1689           0 :                 goto bailout;
    1690             :         }
    1691           8 :         if (old_lg->lg->debug & 1) {
    1692           0 :                 fprintf(stderr, "#logger_new dir set to %s\n", old_lg->lg->dir);
    1693             :         }
    1694             : 
    1695           8 :         if (logger_load(fn, filename, old_lg, fp, version) == GDK_SUCCEED) {
    1696           8 :                 return old_lg;
    1697             :         }
    1698             :         return NULL;
    1699             : 
    1700           0 :   bailout:
    1701           0 :         logbat_destroy(old_lg->add);
    1702           0 :         logbat_destroy(old_lg->del);
    1703           0 :         GDKfree(old_lg);
    1704           0 :         fclose(fp);
    1705           0 :         return NULL;
    1706             : }
    1707             : 
    1708             : static gdk_return
    1709           8 : old_logger_destroy(old_logger *lg)
    1710             : {
    1711             :         BUN p, q;
    1712             :         BAT *b = NULL;
    1713             :         const log_bid *bids;
    1714             :         gdk_return rc;
    1715             : 
    1716           8 :         bat *subcommit = GDKmalloc(sizeof(log_bid) * (BATcount(lg->add) + BATcount(lg->del) + 1));
    1717           8 :         if (subcommit == NULL) {
    1718           0 :                 TRC_CRITICAL(GDK, "logger_destroy failed\n");
    1719           0 :                 return GDK_FAIL;
    1720             :         }
    1721             :         int i = 0;
    1722           8 :         subcommit[i++] = 0;
    1723             : 
    1724           8 :         bids = (const log_bid *) Tloc(lg->add, 0);
    1725         550 :         BATloop(lg->add, p, q) {
    1726         542 :                 b = BATdescriptor(bids[p]);
    1727         542 :                 if (b) {
    1728         542 :                         BATmode(b, false);
    1729         542 :                         BBPunfix(bids[p]);
    1730             :                 }
    1731         542 :                 subcommit[i++] = bids[p];
    1732             :         }
    1733           8 :         bids = (const log_bid *) Tloc(lg->del, 0);
    1734         562 :         BATloop(lg->del, p, q) {
    1735         554 :                 b = BATdescriptor(bids[p]);
    1736         554 :                 if (b) {
    1737         554 :                         BATmode(b, true);
    1738         554 :                         BBPunfix(bids[p]);
    1739             :                 }
    1740         554 :                 subcommit[i++] = bids[p];
    1741             :         }
    1742             :         /* give the catalog bats names so we can find them
    1743             :          * next time */
    1744             :         char bak[IDLENGTH];
    1745          16 :         if (BBPrename(lg->catalog_bid->batCacheid, NULL) < 0 ||
    1746          16 :             BBPrename(lg->catalog_nme->batCacheid, NULL) < 0 ||
    1747          16 :             BBPrename(lg->catalog_tpe->batCacheid, NULL) < 0 ||
    1748          16 :             BBPrename(lg->catalog_oid->batCacheid, NULL) < 0 ||
    1749          16 :             BBPrename(lg->dcatalog->batCacheid, NULL) < 0 ||
    1750          16 :             BBPrename(lg->snapshots_bid->batCacheid, NULL) < 0 ||
    1751          16 :             BBPrename(lg->snapshots_tid->batCacheid, NULL) < 0 ||
    1752          16 :             BBPrename(lg->dsnapshots->batCacheid, NULL) < 0 ||
    1753          16 :             strconcat_len(bak, sizeof(bak), lg->lg->fn, "_catalog_bid", NULL) >= sizeof(bak) ||
    1754          16 :             BBPrename(lg->lg->catalog_bid->batCacheid, bak) < 0 ||
    1755          16 :             strconcat_len(bak, sizeof(bak), lg->lg->fn, "_catalog_id", NULL) >= sizeof(bak) ||
    1756          16 :             BBPrename(lg->lg->catalog_id->batCacheid, bak) < 0 ||
    1757          16 :             strconcat_len(bak, sizeof(bak), lg->lg->fn, "_dcatalog", NULL) >= sizeof(bak) ||
    1758           8 :             BBPrename(lg->lg->dcatalog->batCacheid, bak) < 0) {
    1759           0 :                 GDKfree(subcommit);
    1760           0 :                 return GDK_FAIL;
    1761             :         }
    1762           8 :         if ((rc = GDKmove(0, lg->lg->dir, LOGFILE, NULL, lg->lg->dir, LOGFILE, "bak", true)) != GDK_SUCCEED) {
    1763           0 :                 TRC_CRITICAL(GDK, "logger_destroy failed\n");
    1764           0 :                 GDKfree(subcommit);
    1765           0 :                 return rc;
    1766             :         }
    1767           8 :         if ((rc = logger_create_types_file(lg->lg, lg->filename)) != GDK_SUCCEED) {
    1768           0 :                 TRC_CRITICAL(GDK, "logger_destroy failed\n");
    1769           0 :                 GDKfree(subcommit);
    1770           0 :                 return rc;
    1771             :         }
    1772           8 :         lg->lg->id = (ulng) lg->id;
    1773           8 :         lg->lg->saved_id = lg->lg->id;
    1774           8 :         rc = TMsubcommit_list(subcommit, NULL, i, lg->lg->saved_id, lg->lg->saved_tid);
    1775           8 :         GDKfree(subcommit);
    1776           8 :         if (rc != GDK_SUCCEED) {
    1777           0 :                 TRC_CRITICAL(GDK, "logger_destroy failed\n");
    1778           0 :                 return rc;
    1779             :         }
    1780           8 :         snprintf(bak, sizeof(bak), "bak-" LLFMT, lg->id);
    1781           8 :         if ((rc = GDKmove(0, lg->lg->dir, LOGFILE, "bak", lg->lg->dir, LOGFILE, bak, true)) != GDK_SUCCEED) {
    1782           0 :                 TRC_CRITICAL(GDK, "logger_destroy failed\n");
    1783           0 :                 return rc;
    1784             :         }
    1785             : 
    1786           8 :         if (logger_cleanup(lg) != GDK_SUCCEED)
    1787           0 :                 TRC_CRITICAL(GDK, "logger_cleanup failed\n");
    1788             : 
    1789             :         /* free resources */
    1790           8 :         bids = (const log_bid *) Tloc(lg->catalog_bid, 0);
    1791        3472 :         BATloop(lg->catalog_bid, p, q) {
    1792        3464 :                 bat bid = bids[p];
    1793        3464 :                 oid pos = p;
    1794             : 
    1795        3464 :                 if (BUNfnd(lg->dcatalog, &pos) == BUN_NONE)
    1796        2323 :                         BBPrelease(bid);
    1797             :         }
    1798           8 :         bids = (const log_bid *) Tloc(lg->add, 0);
    1799         550 :         BATloop(lg->add, p, q) {
    1800         542 :                 BBPrelease(bids[p]);
    1801             :         }
    1802           8 :         logbat_destroy(lg->add);
    1803           8 :         bids = (const log_bid *) Tloc(lg->del, 0);
    1804         562 :         BATloop(lg->del, p, q) {
    1805         554 :                 BBPrelease(bids[p]);
    1806             :         }
    1807           8 :         logbat_destroy(lg->del);
    1808             : 
    1809           8 :         logbat_destroy(lg->catalog_bid);
    1810           8 :         logbat_destroy(lg->catalog_nme);
    1811           8 :         logbat_destroy(lg->catalog_tpe);
    1812           8 :         logbat_destroy(lg->catalog_oid);
    1813           8 :         logbat_destroy(lg->dcatalog);
    1814           8 :         logbat_destroy(lg->freed);
    1815           8 :         logbat_destroy(lg->seqs_id);
    1816           8 :         logbat_destroy(lg->seqs_val);
    1817           8 :         logbat_destroy(lg->dseqs);
    1818           8 :         logbat_destroy(lg->snapshots_bid);
    1819           8 :         logbat_destroy(lg->snapshots_tid);
    1820           8 :         logbat_destroy(lg->dsnapshots);
    1821             : 
    1822           8 :         GDKfree(lg);
    1823           8 :         return GDK_SUCCEED;
    1824             : }
    1825             : 
    1826             : /* Create a new logger */
    1827             : gdk_return
    1828           8 : old_logger_load(logger *lg, const char *fn, const char *logdir, FILE *fp, int version, const char *filename)
    1829             : {
    1830             :         old_logger *old_lg;
    1831           8 :         old_lg = logger_new(lg, fn, logdir, fp, version, filename);
    1832           8 :         if (old_lg == NULL)
    1833             :                 return GDK_FAIL;
    1834           8 :         old_logger_destroy(old_lg);
    1835           8 :         return GDK_SUCCEED;
    1836             : }
    1837             : 
    1838             : /* Clean-up write-ahead log files already persisted in the BATs.
    1839             :  * Update the LOGFILE and delete all bak- files as well.
    1840             :  */
    1841             : static gdk_return
    1842           8 : logger_cleanup(old_logger *lg)
    1843             : {
    1844             :         char buf[BUFSIZ];
    1845             :         FILE *fp = NULL;
    1846             : 
    1847           8 :         if (LOG_DISABLED(lg))
    1848             :                 return GDK_SUCCEED;
    1849             : 
    1850           8 :         if (snprintf(buf, sizeof(buf), "%s%s.bak-" LLFMT, lg->lg->dir, LOGFILE, lg->id) >= (int) sizeof(buf)) {
    1851           0 :                 TRC_CRITICAL(GDK, "filename is too large\n");
    1852           0 :                 return GDK_FAIL;
    1853             :         }
    1854             : 
    1855           8 :         if (lg->lg->debug & 1) {
    1856           0 :                 fprintf(stderr, "#logger_cleanup %s\n", buf);
    1857             :         }
    1858             : 
    1859           8 :         lng lid = lg->id;
    1860             :         // remove the last persisted WAL files as well to reduce the
    1861             :         // work for the logger_cleanup_old()
    1862           8 :         if ((fp = GDKfileopen(0, NULL, buf, NULL, "r")) == NULL) {
    1863           0 :                 GDKsyserror("cannot open file %s\n", buf);
    1864             :                 return GDK_FAIL;
    1865             :         }
    1866             : 
    1867         240 :         while (lid-- > 0) {
    1868             :                 char log_id[FILENAME_MAX];
    1869             : 
    1870         232 :                 if (snprintf(log_id, sizeof(log_id), LLFMT, lid) >= (int) sizeof(log_id)) {
    1871           0 :                         TRC_CRITICAL(GDK, "log_id filename is too large\n");
    1872           0 :                         fclose(fp);
    1873           0 :                         return GDK_FAIL;
    1874             :                 }
    1875         232 :                 if (GDKunlink(0, lg->lg->dir, LOGFILE, log_id) != GDK_SUCCEED) {
    1876             :                         /* not a disaster (yet?) if unlink fails */
    1877           0 :                         TRC_ERROR(GDK, "failed to remove old WAL %s.%s\n", LOGFILE, buf);
    1878           0 :                         GDKclrerr();
    1879             :                 }
    1880             :         }
    1881           8 :         fclose(fp);
    1882             : 
    1883           8 :         if (snprintf(buf, sizeof(buf), "bak-" LLFMT, lg->id) >= (int) sizeof(buf)) {
    1884           0 :                 TRC_CRITICAL(GDK, "filename is too large\n");
    1885           0 :                 GDKclrerr();
    1886             :         }
    1887             : 
    1888           8 :         if (GDKunlink(0, lg->lg->dir, LOGFILE, buf) != GDK_SUCCEED) {
    1889             :                 /* not a disaster (yet?) if unlink fails */
    1890           0 :                 TRC_ERROR(GDK, "failed to remove old WAL %s.%s\n", LOGFILE, buf);
    1891           0 :                 GDKclrerr();
    1892             :         }
    1893             : 
    1894             :         return GDK_SUCCEED;
    1895             : }
    1896             : 
    1897             : static gdk_return
    1898           0 : logger_add_bat(old_logger *lg, BAT *b, const char *name, char tpe, oid id)
    1899             : {
    1900           0 :         log_bid bid = old_logger_find_bat(lg, name, tpe, id);
    1901           0 :         lng lid = tpe ? (lng) id : 0;
    1902             : 
    1903           0 :         assert(b->batRestricted != BAT_WRITE ||
    1904             :                b == lg->snapshots_bid ||
    1905             :                b == lg->snapshots_tid ||
    1906             :                b == lg->dsnapshots ||
    1907             :                b == lg->catalog_bid ||
    1908             :                b == lg->catalog_nme ||
    1909             :                b == lg->catalog_tpe ||
    1910             :                b == lg->catalog_oid ||
    1911             :                b == lg->dcatalog ||
    1912             :                b == lg->seqs_id ||
    1913             :                b == lg->seqs_val ||
    1914             :                b == lg->dseqs);
    1915           0 :         assert(b->batRole == PERSISTENT);
    1916           0 :         if (bid) {
    1917           0 :                 if (bid != b->batCacheid) {
    1918           0 :                         if (logger_del_bat(lg, bid) != GDK_SUCCEED)
    1919             :                                 return GDK_FAIL;
    1920             :                 } else {
    1921             :                         return GDK_SUCCEED;
    1922             :                 }
    1923             :         }
    1924           0 :         bid = b->batCacheid;
    1925           0 :         if (lg->lg->debug & 1)
    1926           0 :                 fprintf(stderr, "#create %s\n", NAME(name, tpe, id));
    1927           0 :         assert(log_find(lg->catalog_bid, lg->dcatalog, bid) == BUN_NONE);
    1928           0 :         lg->changes += BATcount(b) + 1000;
    1929           0 :         if (BUNappend(lg->catalog_bid, &bid, false) != GDK_SUCCEED ||
    1930           0 :             BUNappend(lg->catalog_nme, name, false) != GDK_SUCCEED ||
    1931           0 :             BUNappend(lg->catalog_tpe, &tpe, false) != GDK_SUCCEED ||
    1932           0 :             BUNappend(lg->catalog_oid, &lid, false) != GDK_SUCCEED)
    1933           0 :                 return GDK_FAIL;
    1934           0 :         BBPretain(bid);
    1935           0 :         return GDK_SUCCEED;
    1936             : }
    1937             : 
    1938             : 
    1939             : static gdk_return
    1940           0 : logger_del_bat(old_logger *lg, log_bid bid)
    1941             : {
    1942           0 :         BAT *b = BATdescriptor(bid);
    1943           0 :         BUN p = log_find(lg->catalog_bid, lg->dcatalog, bid), q;
    1944             :         oid pos;
    1945             : 
    1946           0 :         assert(p != BUN_NONE);
    1947             :         if (p == BUN_NONE) {
    1948             :                 logbat_destroy(b);
    1949             :                 GDKerror("cannot find BAT\n");
    1950             :                 return GDK_FAIL;
    1951             :         }
    1952             : 
    1953             :         /* if this is a not logger commited snapshot bat, make it
    1954             :          * transient */
    1955           0 :         if (p >= lg->catalog_bid->batInserted &&
    1956           0 :             (q = log_find(lg->snapshots_bid, lg->dsnapshots, bid)) != BUN_NONE) {
    1957           0 :                 pos = (oid) q;
    1958           0 :                 if (BUNappend(lg->dsnapshots, &pos, false) != GDK_SUCCEED) {
    1959             :                         logbat_destroy(b);
    1960           0 :                         return GDK_FAIL;
    1961             :                 }
    1962           0 :                 if (lg->lg->debug & 1)
    1963           0 :                         fprintf(stderr,
    1964             :                                 "#logger_del_bat release snapshot %d (%d)\n",
    1965           0 :                                 bid, BBP_lrefs(bid));
    1966           0 :                 if (BUNappend(lg->freed, &bid, false) != GDK_SUCCEED) {
    1967             :                         logbat_destroy(b);
    1968           0 :                         return GDK_FAIL;
    1969             :                 }
    1970           0 :         } else if (p >= lg->catalog_bid->batInserted) {
    1971           0 :                 BBPrelease(bid);
    1972             :         } else {
    1973           0 :                 if (BUNappend(lg->freed, &bid, false) != GDK_SUCCEED) {
    1974             :                         logbat_destroy(b);
    1975           0 :                         return GDK_FAIL;
    1976             :                 }
    1977             :         }
    1978           0 :         if (b) {
    1979           0 :                 lg->changes += BATcount(b) + 1;
    1980           0 :                 BBPunfix(b->batCacheid);
    1981             :         }
    1982           0 :         pos = (oid) p;
    1983           0 :         return BUNappend(lg->dcatalog, &pos, false);
    1984             : /*assert(BBP_lrefs(bid) == 0);*/
    1985             : }
    1986             : 
    1987             : static geomcatalogfix_fptr geomcatalogfix = NULL;
    1988             : static geomsqlfix_fptr geomsqlfix = NULL;
    1989             : 
    1990             : void
    1991           0 : geomcatalogfix_set(geomcatalogfix_fptr f)
    1992             : {
    1993           0 :         geomcatalogfix = f;
    1994           0 : }
    1995             : 
    1996             : geomcatalogfix_fptr
    1997           0 : geomcatalogfix_get(void)
    1998             : {
    1999           0 :         return geomcatalogfix;
    2000             : }
    2001             : 
    2002             : void
    2003           0 : geomsqlfix_set(geomsqlfix_fptr f)
    2004             : {
    2005           0 :         geomsqlfix = f;
    2006           0 : }
    2007             : 
    2008             : geomsqlfix_fptr
    2009           0 : geomsqlfix_get(void)
    2010             : {
    2011           0 :         return geomsqlfix;
    2012             : }
    2013             : 
    2014             : void
    2015           0 : geomversion_set(void)
    2016             : {
    2017           0 :         geomisoldversion = true;
    2018           0 : }
    2019             : 
    2020             : bool
    2021           0 : geomversion_get(void)
    2022             : {
    2023           0 :         return geomisoldversion;
    2024             : }

Generated by: LCOV version 1.14