Coverage Report

Created: 2026-10-17 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/reftable/stack.c
Line
Count
Source
1
/*
2
 * Copyright 2020 Google LLC
3
 *
4
 * Use of this source code is governed by a BSD-style
5
 * license that can be found in the LICENSE file or at
6
 * https://developers.google.com/open-source/licenses/bsd
7
 */
8
9
#include "stack.h"
10
11
#include "system.h"
12
#include "constants.h"
13
#include "merged.h"
14
#include "reftable-error.h"
15
#include "reftable-record.h"
16
#include "reftable-merged.h"
17
#include "table.h"
18
#include "writer.h"
19
20
static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st,
21
        const char *name)
22
0
{
23
0
  int err;
24
0
  reftable_buf_reset(dest);
25
0
  if ((err = reftable_buf_addstr(dest, st->reftable_dir)) < 0 ||
26
0
      (err = reftable_buf_addstr(dest, "/")) < 0 ||
27
0
      (err = reftable_buf_addstr(dest, name)) < 0)
28
0
    return err;
29
0
  return 0;
30
0
}
31
32
static ssize_t reftable_write_data(int fd, const void *data, size_t size)
33
0
{
34
0
  size_t total_written = 0;
35
0
  const char *p = data;
36
37
0
  while (total_written < size) {
38
0
    ssize_t bytes_written = write(fd, p, size - total_written);
39
0
    if (bytes_written < 0 && (errno == EAGAIN || errno == EINTR))
40
0
      continue;
41
0
    if (bytes_written < 0)
42
0
      return REFTABLE_IO_ERROR;
43
44
0
    total_written += bytes_written;
45
0
    p += bytes_written;
46
0
  }
47
48
0
  return total_written;
49
0
}
50
51
struct fd_writer {
52
  const struct reftable_write_options *opts;
53
  int fd;
54
};
55
56
static ssize_t fd_writer_write(void *arg, const void *data, size_t sz)
57
0
{
58
0
  struct fd_writer *writer = arg;
59
0
  return reftable_write_data(writer->fd, data, sz);
60
0
}
61
62
static int fd_writer_flush(void *arg)
63
0
{
64
0
  struct fd_writer *writer = arg;
65
0
  return fsync(writer->fd);
66
0
}
67
68
static int fd_read_lines(int fd, char ***namesp)
69
0
{
70
0
  char *buf = NULL;
71
0
  int err = 0;
72
0
  off_t size;
73
74
0
  size = lseek(fd, 0, SEEK_END);
75
0
  if (size < 0) {
76
0
    err = REFTABLE_IO_ERROR;
77
0
    goto done;
78
0
  }
79
80
0
  err = lseek(fd, 0, SEEK_SET);
81
0
  if (err < 0) {
82
0
    err = REFTABLE_IO_ERROR;
83
0
    goto done;
84
0
  }
85
86
0
  REFTABLE_ALLOC_ARRAY(buf, size + 1);
87
0
  if (!buf) {
88
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
89
0
    goto done;
90
0
  }
91
92
0
  for (off_t total_read = 0; total_read < size; ) {
93
0
    ssize_t bytes_read = read(fd, buf + total_read, size - total_read);
94
0
    if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
95
0
      continue;
96
0
    if (bytes_read < 0 || !bytes_read) {
97
0
      err = REFTABLE_IO_ERROR;
98
0
      goto done;
99
0
    }
100
101
0
    total_read += bytes_read;
102
0
  }
103
0
  buf[size] = 0;
104
105
0
  err = parse_names(buf, size, namesp);
106
0
done:
107
0
  reftable_free(buf);
108
0
  return err;
109
0
}
110
111
int read_lines(const char *filename, char ***namesp)
112
0
{
113
0
  int fd = open(filename, O_RDONLY);
114
0
  int err = 0;
115
0
  if (fd < 0) {
116
0
    if (errno == ENOENT) {
117
0
      REFTABLE_CALLOC_ARRAY(*namesp, 1);
118
0
      if (!*namesp)
119
0
        return REFTABLE_OUT_OF_MEMORY_ERROR;
120
0
      return 0;
121
0
    }
122
123
0
    return REFTABLE_IO_ERROR;
124
0
  }
125
0
  err = fd_read_lines(fd, namesp);
126
0
  close(fd);
127
0
  return err;
128
0
}
129
130
int reftable_stack_init_ref_iterator(struct reftable_stack *st,
131
              struct reftable_iterator *it)
132
0
{
133
0
  return merged_table_init_iter(reftable_stack_merged_table(st),
134
0
              it, REFTABLE_BLOCK_TYPE_REF);
135
0
}
136
137
int reftable_stack_init_log_iterator(struct reftable_stack *st,
138
             struct reftable_iterator *it)
139
0
{
140
0
  return merged_table_init_iter(reftable_stack_merged_table(st),
141
0
              it, REFTABLE_BLOCK_TYPE_LOG);
142
0
}
143
144
struct reftable_merged_table *
145
reftable_stack_merged_table(struct reftable_stack *st)
146
0
{
147
0
  return st->merged;
148
0
}
149
150
static int has_name(char **names, const char *name)
151
0
{
152
0
  while (*names) {
153
0
    if (!strcmp(*names, name))
154
0
      return 1;
155
0
    names++;
156
0
  }
157
0
  return 0;
158
0
}
159
160
/* Close and free the stack */
161
void reftable_stack_destroy(struct reftable_stack *st)
162
0
{
163
0
  char **names = NULL;
164
0
  int err = 0;
165
166
0
  if (!st)
167
0
    return;
168
169
0
  if (st->merged) {
170
0
    reftable_merged_table_free(st->merged);
171
0
    st->merged = NULL;
172
0
  }
173
174
0
  if (st->list_file)
175
0
    err = read_lines(st->list_file, &names);
176
0
  if (err < 0) {
177
0
    REFTABLE_FREE_AND_NULL(names);
178
0
  }
179
180
0
  if (st->tables) {
181
0
    struct reftable_buf filename = REFTABLE_BUF_INIT;
182
183
0
    for (size_t i = 0; i < st->tables_len; i++) {
184
0
      const char *name = reftable_table_name(st->tables[i]);
185
0
      int try_unlinking = 1;
186
187
0
      reftable_buf_reset(&filename);
188
0
      if (names && !has_name(names, name)) {
189
0
        if (stack_filename(&filename, st, name) < 0)
190
0
          try_unlinking = 0;
191
0
      }
192
0
      reftable_table_decref(st->tables[i]);
193
194
0
      if (try_unlinking && filename.len) {
195
        /* On Windows, can only unlink after closing. */
196
0
        unlink(filename.buf);
197
0
      }
198
0
    }
199
200
0
    reftable_buf_release(&filename);
201
0
    st->tables_len = 0;
202
0
    REFTABLE_FREE_AND_NULL(st->tables);
203
0
  }
204
205
0
  if (st->list_fd >= 0) {
206
0
    close(st->list_fd);
207
0
    st->list_fd = -1;
208
0
  }
209
210
0
  REFTABLE_FREE_AND_NULL(st->list_file);
211
0
  REFTABLE_FREE_AND_NULL(st->reftable_dir);
212
0
  reftable_free(st);
213
0
  free_names(names);
214
0
}
215
216
static struct reftable_table **stack_copy_tables(struct reftable_stack *st,
217
             size_t cur_len)
218
0
{
219
0
  struct reftable_table **cur = reftable_calloc(cur_len, sizeof(*cur));
220
0
  if (!cur)
221
0
    return NULL;
222
0
  for (size_t i = 0; i < cur_len; i++)
223
0
    cur[i] = st->tables[i];
224
0
  return cur;
225
0
}
226
227
static int reftable_stack_reload_once(struct reftable_stack *st,
228
              const char **names,
229
              int reuse_open)
230
0
{
231
0
  size_t cur_len = !st->merged ? 0 : st->merged->tables_len;
232
0
  struct reftable_table **cur = NULL;
233
0
  struct reftable_table **reused = NULL;
234
0
  struct reftable_table **new_tables = NULL;
235
0
  size_t reused_len = 0, reused_alloc = 0, names_len;
236
0
  size_t new_tables_len = 0;
237
0
  struct reftable_merged_table *new_merged = NULL;
238
0
  struct reftable_buf table_path = REFTABLE_BUF_INIT;
239
0
  int err = 0;
240
0
  size_t i;
241
242
0
  if (cur_len) {
243
0
    cur = stack_copy_tables(st, cur_len);
244
0
    if (!cur) {
245
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
246
0
      goto done;
247
0
    }
248
0
  }
249
250
0
  names_len = names_length(names);
251
252
0
  if (names_len) {
253
0
    new_tables = reftable_calloc(names_len, sizeof(*new_tables));
254
0
    if (!new_tables) {
255
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
256
0
      goto done;
257
0
    }
258
0
  }
259
260
0
  while (*names) {
261
0
    struct reftable_table *table = NULL;
262
0
    const char *name = *names++;
263
264
    /* this is linear; we assume compaction keeps the number of
265
       tables under control so this is not quadratic. */
266
0
    for (i = 0; reuse_open && i < cur_len; i++) {
267
0
      if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
268
0
        table = cur[i];
269
0
        cur[i] = NULL;
270
271
        /*
272
         * When reloading the stack fails, we end up
273
         * releasing all new tables. This also
274
         * includes the reused tables, even though
275
         * they are still in used by the old stack. We
276
         * thus need to keep them alive here, which we
277
         * do by bumping their refcount.
278
         */
279
0
        REFTABLE_ALLOC_GROW_OR_NULL(reused,
280
0
                  reused_len + 1,
281
0
                  reused_alloc);
282
0
        if (!reused) {
283
0
          err = REFTABLE_OUT_OF_MEMORY_ERROR;
284
0
          goto done;
285
0
        }
286
0
        reused[reused_len++] = table;
287
0
        reftable_table_incref(table);
288
0
        break;
289
0
      }
290
0
    }
291
292
0
    if (!table) {
293
0
      struct reftable_block_source src = { NULL };
294
295
0
      err = stack_filename(&table_path, st, name);
296
0
      if (err < 0)
297
0
        goto done;
298
299
0
      err = reftable_block_source_from_file(&src,
300
0
                    table_path.buf);
301
0
      if (err < 0)
302
0
        goto done;
303
304
0
      err = reftable_table_new(&table, &src, name);
305
0
      if (err < 0)
306
0
        goto done;
307
0
    }
308
309
0
    new_tables[new_tables_len] = table;
310
0
    new_tables_len++;
311
0
  }
312
313
  /* success! */
314
0
  err = reftable_merged_table_new(&new_merged, new_tables,
315
0
          new_tables_len, st->opts.hash_id);
316
0
  if (err < 0)
317
0
    goto done;
318
319
  /*
320
   * Close the old, non-reused tables and proactively try to unlink
321
   * them. This is done for systems like Windows, where the underlying
322
   * file of such an open table wouldn't have been possible to be
323
   * unlinked by the compacting process.
324
   */
325
0
  for (i = 0; i < cur_len; i++) {
326
0
    if (cur[i]) {
327
0
      const char *name = reftable_table_name(cur[i]);
328
329
0
      err = stack_filename(&table_path, st, name);
330
0
      if (err < 0)
331
0
        goto done;
332
333
0
      reftable_table_decref(cur[i]);
334
0
      unlink(table_path.buf);
335
0
    }
336
0
  }
337
338
  /* Update the stack to point to the new tables. */
339
0
  if (st->merged)
340
0
    reftable_merged_table_free(st->merged);
341
0
  new_merged->suppress_deletions = st->opts.suppress_deletions;
342
0
  st->merged = new_merged;
343
344
0
  if (st->tables)
345
0
    reftable_free(st->tables);
346
0
  st->tables = new_tables;
347
0
  st->tables_len = new_tables_len;
348
0
  new_tables = NULL;
349
0
  new_tables_len = 0;
350
351
  /*
352
   * Decrement the refcount of reused tables again. This only needs to
353
   * happen on the successful case, because on the unsuccessful one we
354
   * decrement their refcount via `new_tables`.
355
   */
356
0
  for (i = 0; i < reused_len; i++)
357
0
    reftable_table_decref(reused[i]);
358
359
0
done:
360
0
  for (i = 0; i < new_tables_len; i++)
361
0
    reftable_table_decref(new_tables[i]);
362
0
  reftable_free(new_tables);
363
0
  reftable_free(reused);
364
0
  reftable_free(cur);
365
0
  reftable_buf_release(&table_path);
366
0
  return err;
367
0
}
368
369
static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
370
               int reuse_open)
371
0
{
372
0
  char **names = NULL, **names_after = NULL;
373
0
  uint64_t deadline;
374
0
  int64_t delay = 0;
375
0
  int tries = 0, err;
376
0
  int fd = -1;
377
378
0
  deadline = reftable_time_ms() + 3000;
379
380
0
  while (1) {
381
0
    uint64_t now = reftable_time_ms();
382
383
    /*
384
     * Only look at deadlines after the first few times. This
385
     * simplifies debugging in GDB.
386
     */
387
0
    tries++;
388
0
    if (tries > 3 && now >= deadline)
389
0
      goto out;
390
391
0
    fd = open(st->list_file, O_RDONLY);
392
0
    if (fd < 0) {
393
0
      if (errno != ENOENT) {
394
0
        err = REFTABLE_IO_ERROR;
395
0
        goto out;
396
0
      }
397
398
0
      REFTABLE_CALLOC_ARRAY(names, 1);
399
0
      if (!names) {
400
0
        err = REFTABLE_OUT_OF_MEMORY_ERROR;
401
0
        goto out;
402
0
      }
403
0
    } else {
404
0
      err = fd_read_lines(fd, &names);
405
0
      if (err < 0)
406
0
        goto out;
407
0
    }
408
409
0
    err = reftable_stack_reload_once(st, (const char **) names, reuse_open);
410
0
    if (!err)
411
0
      break;
412
0
    if (err != REFTABLE_NOT_EXIST_ERROR)
413
0
      goto out;
414
415
    /*
416
     * REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
417
     * writer. Check if there was one by checking if the name list
418
     * changed.
419
     */
420
0
    err = read_lines(st->list_file, &names_after);
421
0
    if (err < 0)
422
0
      goto out;
423
0
    if (names_equal((const char **) names_after,
424
0
        (const char **) names)) {
425
0
      err = REFTABLE_NOT_EXIST_ERROR;
426
0
      goto out;
427
0
    }
428
429
0
    free_names(names);
430
0
    names = NULL;
431
0
    free_names(names_after);
432
0
    names_after = NULL;
433
0
    close(fd);
434
0
    fd = -1;
435
436
0
    delay = delay + (delay * reftable_rand()) / UINT32_MAX + 1;
437
0
    poll(NULL, 0, delay);
438
0
  }
439
440
0
out:
441
  /*
442
   * Invalidate the stat cache. It is sufficient to only close the file
443
   * descriptor and keep the cached stat info because we never use the
444
   * latter when the former is negative.
445
   */
446
0
  if (st->list_fd >= 0) {
447
0
    close(st->list_fd);
448
0
    st->list_fd = -1;
449
0
  }
450
451
  /*
452
   * Cache stat information in case it provides a useful signal to us.
453
   * According to POSIX, "The st_ino and st_dev fields taken together
454
   * uniquely identify the file within the system." That being said,
455
   * Windows is not POSIX compliant and we do not have these fields
456
   * available. So the information we have there is insufficient to
457
   * determine whether two file descriptors point to the same file.
458
   *
459
   * While we could fall back to using other signals like the file's
460
   * mtime, those are not sufficient to avoid races. We thus refrain from
461
   * using the stat cache on such systems and fall back to the secondary
462
   * caching mechanism, which is to check whether contents of the file
463
   * have changed.
464
   *
465
   * On other systems which are POSIX compliant we must keep the file
466
   * descriptor open. This is to avoid a race condition where two
467
   * processes access the reftable stack at the same point in time:
468
   *
469
   *   1. A reads the reftable stack and caches its stat info.
470
   *
471
   *   2. B updates the stack, appending a new table to "tables.list".
472
   *      This will both use a new inode and result in a different file
473
   *      size, thus invalidating A's cache in theory.
474
   *
475
   *   3. B decides to auto-compact the stack and merges two tables. The
476
   *      file size now matches what A has cached again. Furthermore, the
477
   *      filesystem may decide to recycle the inode number of the file
478
   *      we have replaced in (2) because it is not in use anymore.
479
   *
480
   *   4. A reloads the reftable stack. Neither the inode number nor the
481
   *      file size changed. If the timestamps did not change either then
482
   *      we think the cached copy of our stack is up-to-date.
483
   *
484
   * By keeping the file descriptor open the inode number cannot be
485
   * recycled, mitigating the race.
486
   */
487
0
  if (!err && fd >= 0 && !fstat(fd, &st->list_st) &&
488
0
      st->list_st.st_dev && st->list_st.st_ino) {
489
0
    st->list_fd = fd;
490
0
    fd = -1;
491
0
  }
492
493
0
  if (fd >= 0)
494
0
    close(fd);
495
0
  free_names(names);
496
0
  free_names(names_after);
497
498
0
  if (st->opts.on_reload)
499
0
    st->opts.on_reload(st->opts.on_reload_payload);
500
501
0
  return err;
502
0
}
503
504
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
505
           const struct reftable_stack_options *_opts)
506
0
{
507
0
  struct reftable_buf list_file_name = REFTABLE_BUF_INIT;
508
0
  struct reftable_stack_options opts = { 0 };
509
0
  struct reftable_stack *p;
510
0
  int err;
511
512
0
  p = reftable_calloc(1, sizeof(*p));
513
0
  if (!p) {
514
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
515
0
    goto out;
516
0
  }
517
518
0
  if (_opts)
519
0
    opts = *_opts;
520
0
  if (opts.hash_id == 0)
521
0
    opts.hash_id = REFTABLE_HASH_SHA1;
522
523
0
  *dest = NULL;
524
525
0
  reftable_buf_reset(&list_file_name);
526
0
  if ((err = reftable_buf_addstr(&list_file_name, dir)) < 0 ||
527
0
      (err = reftable_buf_addstr(&list_file_name, "/tables.list")) < 0)
528
0
    goto out;
529
530
0
  p->list_file = reftable_buf_detach(&list_file_name);
531
0
  p->list_fd = -1;
532
0
  p->opts = opts;
533
0
  p->reftable_dir = reftable_strdup(dir);
534
0
  if (!p->reftable_dir) {
535
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
536
0
    goto out;
537
0
  }
538
539
0
  p->list_lock = REFTABLE_FLOCK_INIT;
540
541
0
  err = reftable_stack_reload_maybe_reuse(p, 1);
542
0
  if (err < 0)
543
0
    goto out;
544
545
0
  *dest = p;
546
0
  err = 0;
547
548
0
out:
549
0
  if (err < 0)
550
0
    reftable_stack_destroy(p);
551
0
  return err;
552
0
}
553
554
/*
555
 * Check whether the given stack is up-to-date with what we have in memory.
556
 * If skip_if_locked is set skip stack reloading if the stack is currently
557
 * locked. Stack reloading must _not_ be skipped right after obtaining the
558
 * lock, to check for concurrent updates which may have happened.
559
 *
560
 * Returns 0 if so, 1 if the stack is out-of-date or a negative error code
561
 * otherwise.
562
 */
563
static int stack_uptodate(struct reftable_stack *st, int skip_if_locked)
564
0
{
565
0
  char **names = NULL;
566
0
  int err;
567
568
0
  if (skip_if_locked && st->list_lock.fd != -1)
569
0
    return 0;
570
571
  /*
572
   * When we have cached stat information available then we use it to
573
   * verify whether the file has been rewritten.
574
   *
575
   * Note that we explicitly do not want to use `stat_validity_check()`
576
   * and friends here because they may end up not comparing the `st_dev`
577
   * and `st_ino` fields. These functions thus cannot guarantee that we
578
   * indeed still have the same file.
579
   */
580
0
  if (st->list_fd >= 0) {
581
0
    struct stat list_st;
582
583
0
    if (stat(st->list_file, &list_st) < 0) {
584
      /*
585
       * It's fine for "tables.list" to not exist. In that
586
       * case, we have to refresh when the loaded stack has
587
       * any tables.
588
       */
589
0
      if (errno == ENOENT)
590
0
        return !!st->tables_len;
591
0
      return REFTABLE_IO_ERROR;
592
0
    }
593
594
    /*
595
     * When "tables.list" refers to the same file we can assume
596
     * that it didn't change. This is because we always use
597
     * rename(3P) to update the file and never write to it
598
     * directly.
599
     */
600
0
    if (st->list_st.st_dev == list_st.st_dev &&
601
0
        st->list_st.st_ino == list_st.st_ino)
602
0
      return 0;
603
0
  }
604
605
0
  err = read_lines(st->list_file, &names);
606
0
  if (err < 0)
607
0
    return err;
608
609
0
  for (size_t i = 0; i < st->tables_len; i++) {
610
0
    if (!names[i]) {
611
0
      err = 1;
612
0
      goto done;
613
0
    }
614
615
0
    if (strcmp(st->tables[i]->name, names[i])) {
616
0
      err = 1;
617
0
      goto done;
618
0
    }
619
0
  }
620
621
0
  if (names[st->merged->tables_len]) {
622
0
    err = 1;
623
0
    goto done;
624
0
  }
625
626
0
done:
627
0
  free_names(names);
628
0
  return err;
629
0
}
630
631
int reftable_stack_reload(struct reftable_stack *st)
632
0
{
633
0
  int err = stack_uptodate(st, 1);
634
0
  if (err > 0)
635
0
    return reftable_stack_reload_maybe_reuse(st, 1);
636
0
  return err;
637
0
}
638
639
struct reftable_addition {
640
  struct reftable_stack *stack;
641
  struct reftable_write_options opts;
642
643
  /*
644
   * While the list lock is acquired on the stack, we need to distinguish
645
   * which 'reftable_addition' is responsible for the lock. This avoids
646
   * clearing the lock of another 'reftable_addition'.
647
   */
648
  unsigned int locked : 1;
649
650
  char **new_tables;
651
  size_t new_tables_len, new_tables_cap;
652
  uint64_t next_update_index;
653
};
654
655
static void reftable_addition_close(struct reftable_addition *add)
656
0
{
657
0
  struct reftable_buf nm = REFTABLE_BUF_INIT;
658
0
  size_t i;
659
660
0
  for (i = 0; i < add->new_tables_len; i++) {
661
0
    if (!stack_filename(&nm, add->stack, add->new_tables[i]))
662
0
      unlink(nm.buf);
663
0
    reftable_free(add->new_tables[i]);
664
0
    add->new_tables[i] = NULL;
665
0
  }
666
0
  reftable_free(add->new_tables);
667
0
  add->new_tables = NULL;
668
0
  add->new_tables_len = 0;
669
0
  add->new_tables_cap = 0;
670
671
0
  if (add->locked)
672
0
    flock_release(&add->stack->list_lock);
673
0
  add->locked = 0;
674
0
  reftable_buf_release(&nm);
675
0
}
676
677
static int reftable_stack_init_addition(struct reftable_addition *add,
678
          struct reftable_stack *st,
679
          const struct reftable_write_options *opts)
680
0
{
681
0
  struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
682
0
  int err;
683
684
0
  memset(add, 0, sizeof(*add));
685
0
  add->stack = st;
686
0
  if (opts)
687
0
    add->opts = *opts;
688
689
0
  err = flock_acquire(&add->stack->list_lock, st->list_file,
690
0
          add->opts.lock_timeout_ms);
691
0
  if (err < 0)
692
0
    goto done;
693
0
  add->locked = 1;
694
695
0
  if (add->opts.default_permissions) {
696
0
    if (chmod(add->stack->list_lock.path,
697
0
        add->opts.default_permissions) < 0) {
698
0
      err = REFTABLE_IO_ERROR;
699
0
      goto done;
700
0
    }
701
0
  }
702
703
0
  err = stack_uptodate(st, 0);
704
0
  if (err < 0)
705
0
    goto done;
706
0
  if (err > 0) {
707
0
    err = reftable_stack_reload_maybe_reuse(add->stack, 1);
708
0
    if (err)
709
0
      goto done;
710
0
  }
711
712
0
  add->next_update_index = reftable_stack_next_update_index(st);
713
0
done:
714
0
  if (err)
715
0
    reftable_addition_close(add);
716
0
  reftable_buf_release(&lock_file_name);
717
0
  return err;
718
0
}
719
720
static int stack_try_add(struct reftable_stack *st,
721
       int (*write_table)(struct reftable_writer *wr,
722
              void *arg),
723
       void *arg,
724
       const struct reftable_write_options *opts)
725
0
{
726
0
  struct reftable_addition add;
727
0
  int err;
728
729
0
  err = reftable_stack_init_addition(&add, st, opts);
730
0
  if (err < 0)
731
0
    goto done;
732
733
0
  err = reftable_addition_add(&add, write_table, arg);
734
0
  if (err < 0)
735
0
    goto done;
736
737
0
  err = reftable_addition_commit(&add);
738
0
done:
739
0
  reftable_addition_close(&add);
740
0
  return err;
741
0
}
742
743
int reftable_stack_add(struct reftable_stack *st,
744
           int (*write)(struct reftable_writer *wr, void *arg),
745
           void *arg,
746
           const struct reftable_write_options *opts)
747
0
{
748
0
  int err = stack_try_add(st, write, arg, opts);
749
0
  if (err < 0) {
750
0
    return err;
751
0
  }
752
753
0
  return 0;
754
0
}
755
756
static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
757
0
{
758
0
  char buf[100];
759
0
  uint32_t rnd = reftable_rand();
760
0
  snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
761
0
     min, max, rnd);
762
0
  reftable_buf_reset(dest);
763
0
  return reftable_buf_addstr(dest, buf);
764
0
}
765
766
void reftable_addition_destroy(struct reftable_addition *add)
767
0
{
768
0
  if (!add) {
769
0
    return;
770
0
  }
771
0
  reftable_addition_close(add);
772
0
  reftable_free(add);
773
0
}
774
775
int reftable_addition_commit(struct reftable_addition *add)
776
0
{
777
0
  struct reftable_buf table_list = REFTABLE_BUF_INIT;
778
0
  int err = 0;
779
0
  size_t i;
780
781
0
  if (add->new_tables_len == 0)
782
0
    goto done;
783
784
0
  for (i = 0; i < add->stack->merged->tables_len; i++) {
785
0
    if ((err = reftable_buf_addstr(&table_list, add->stack->tables[i]->name)) < 0 ||
786
0
        (err = reftable_buf_addstr(&table_list, "\n")) < 0)
787
0
      goto done;
788
0
  }
789
0
  for (i = 0; i < add->new_tables_len; i++) {
790
0
    if ((err = reftable_buf_addstr(&table_list, add->new_tables[i])) < 0 ||
791
0
        (err = reftable_buf_addstr(&table_list, "\n")) < 0)
792
0
      goto done;
793
0
  }
794
795
0
  err = reftable_write_data(add->stack->list_lock.fd,
796
0
          table_list.buf, table_list.len);
797
0
  reftable_buf_release(&table_list);
798
0
  if (err < 0) {
799
0
    err = REFTABLE_IO_ERROR;
800
0
    goto done;
801
0
  }
802
803
0
  err = fsync(add->stack->list_lock.fd);
804
0
  if (err < 0) {
805
0
    err = REFTABLE_IO_ERROR;
806
0
    goto done;
807
0
  }
808
809
0
  err = flock_commit(&add->stack->list_lock);
810
0
  if (err < 0) {
811
0
    err = REFTABLE_IO_ERROR;
812
0
    goto done;
813
0
  }
814
0
  add->locked = 0;
815
816
  /* success, no more state to clean up. */
817
0
  for (i = 0; i < add->new_tables_len; i++)
818
0
    reftable_free(add->new_tables[i]);
819
0
  reftable_free(add->new_tables);
820
0
  add->new_tables = NULL;
821
0
  add->new_tables_len = 0;
822
0
  add->new_tables_cap = 0;
823
824
0
  err = reftable_stack_reload_maybe_reuse(add->stack, 1);
825
0
  if (err)
826
0
    goto done;
827
828
0
  if (!add->opts.disable_auto_compact) {
829
    /*
830
     * Auto-compact the stack to keep the number of tables in
831
     * control. It is possible that a concurrent writer is already
832
     * trying to compact parts of the stack, which would lead to a
833
     * `REFTABLE_LOCK_ERROR` because parts of the stack are locked
834
     * already. Similarly, the stack may have been rewritten by a
835
     * concurrent writer, which causes `REFTABLE_OUTDATED_ERROR`.
836
     * Both of these errors are benign, so we simply ignore them.
837
     */
838
0
    err = reftable_stack_auto_compact(add->stack, &add->opts);
839
0
    if (err < 0 && err != REFTABLE_LOCK_ERROR &&
840
0
        err != REFTABLE_OUTDATED_ERROR)
841
0
      goto done;
842
0
    err = 0;
843
0
  }
844
845
0
done:
846
0
  reftable_addition_close(add);
847
0
  return err;
848
0
}
849
850
int reftable_stack_addition_new(struct reftable_addition **dest,
851
        struct reftable_stack *st,
852
        const struct reftable_write_options *opts)
853
0
{
854
0
  int err;
855
856
0
  REFTABLE_CALLOC_ARRAY(*dest, 1);
857
0
  if (!*dest)
858
0
    return REFTABLE_OUT_OF_MEMORY_ERROR;
859
860
0
  err = reftable_stack_init_addition(*dest, st, opts);
861
0
  if (err) {
862
0
    reftable_free(*dest);
863
0
    *dest = NULL;
864
0
  }
865
866
0
  return err;
867
0
}
868
869
int reftable_addition_add(struct reftable_addition *add,
870
        int (*write_table)(struct reftable_writer *wr,
871
               void *arg),
872
        void *arg)
873
0
{
874
0
  struct reftable_buf temp_tab_file_name = REFTABLE_BUF_INIT;
875
0
  struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
876
0
  struct reftable_buf next_name = REFTABLE_BUF_INIT;
877
0
  struct reftable_writer *wr = NULL;
878
0
  struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
879
0
  struct fd_writer writer = {
880
0
    .opts = &add->opts,
881
0
  };
882
0
  int err = 0;
883
884
0
  reftable_buf_reset(&next_name);
885
886
0
  err = format_name(&next_name, add->next_update_index, add->next_update_index);
887
0
  if (err < 0)
888
0
    goto done;
889
890
0
  err = stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
891
0
  if (err < 0)
892
0
    goto done;
893
894
0
  err = reftable_buf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
895
0
  if (err < 0)
896
0
    goto done;
897
898
0
  err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf);
899
0
  if (err < 0)
900
0
    goto done;
901
0
  if (add->opts.default_permissions) {
902
0
    if (chmod(tab_file.path,
903
0
        add->opts.default_permissions)) {
904
0
      err = REFTABLE_IO_ERROR;
905
0
      goto done;
906
0
    }
907
0
  }
908
909
0
  writer.fd = tab_file.fd;
910
0
  err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
911
0
          &writer, add->stack->opts.hash_id, &add->opts);
912
0
  if (err < 0)
913
0
    goto done;
914
915
0
  err = write_table(wr, arg);
916
0
  if (err < 0)
917
0
    goto done;
918
919
0
  err = reftable_writer_close(wr);
920
0
  if (err == REFTABLE_EMPTY_TABLE_ERROR) {
921
0
    err = 0;
922
0
    goto done;
923
0
  }
924
0
  if (err < 0)
925
0
    goto done;
926
927
0
  err = tmpfile_close(&tab_file);
928
0
  if (err < 0)
929
0
    goto done;
930
931
0
  if (wr->min_update_index < add->next_update_index) {
932
0
    err = REFTABLE_API_ERROR;
933
0
    goto done;
934
0
  }
935
936
0
  err = format_name(&next_name, wr->min_update_index, wr->max_update_index);
937
0
  if (err < 0)
938
0
    goto done;
939
940
0
  err = reftable_buf_addstr(&next_name, ".ref");
941
0
  if (err < 0)
942
0
    goto done;
943
944
0
  err = stack_filename(&tab_file_name, add->stack, next_name.buf);
945
0
  if (err < 0)
946
0
    goto done;
947
948
  /*
949
    On windows, this relies on rand() picking a unique destination name.
950
    Maybe we should do retry loop as well?
951
   */
952
0
  err = tmpfile_rename(&tab_file, tab_file_name.buf);
953
0
  if (err < 0)
954
0
    goto done;
955
956
0
  REFTABLE_ALLOC_GROW_OR_NULL(add->new_tables, add->new_tables_len + 1,
957
0
            add->new_tables_cap);
958
0
  if (!add->new_tables) {
959
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
960
0
    goto done;
961
0
  }
962
0
  add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
963
964
0
done:
965
0
  tmpfile_delete(&tab_file);
966
0
  reftable_buf_release(&temp_tab_file_name);
967
0
  reftable_buf_release(&tab_file_name);
968
0
  reftable_buf_release(&next_name);
969
0
  reftable_writer_free(wr);
970
0
  return err;
971
0
}
972
973
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
974
0
{
975
0
  int sz = st->merged->tables_len;
976
0
  if (sz > 0)
977
0
    return reftable_table_max_update_index(st->tables[sz - 1]) +
978
0
           1;
979
0
  return 1;
980
0
}
981
982
static int stack_write_compact(struct reftable_stack *st,
983
             struct reftable_writer *wr,
984
             size_t first, size_t last,
985
             struct reftable_log_expiry_config *config)
986
0
{
987
0
  struct reftable_merged_table *mt = NULL;
988
0
  struct reftable_iterator it = { NULL };
989
0
  struct reftable_ref_record ref = { NULL };
990
0
  struct reftable_log_record log = { NULL };
991
0
  size_t subtabs_len = last - first + 1;
992
0
  uint64_t entries = 0;
993
0
  int err = 0;
994
995
0
  for (size_t i = first; i <= last; i++)
996
0
    st->stats.bytes += st->tables[i]->size;
997
0
  err = reftable_writer_set_limits(wr, st->tables[first]->min_update_index,
998
0
           st->tables[last]->max_update_index);
999
0
  if (err < 0)
1000
0
    goto done;
1001
1002
0
  err = reftable_merged_table_new(&mt, st->tables + first, subtabs_len,
1003
0
          st->opts.hash_id);
1004
0
  if (err < 0)
1005
0
    goto done;
1006
1007
0
  err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
1008
0
  if (err < 0)
1009
0
    goto done;
1010
1011
0
  err = reftable_iterator_seek_ref(&it, "");
1012
0
  if (err < 0)
1013
0
    goto done;
1014
1015
0
  while (1) {
1016
0
    err = reftable_iterator_next_ref(&it, &ref);
1017
0
    if (err > 0) {
1018
0
      err = 0;
1019
0
      break;
1020
0
    }
1021
0
    if (err < 0)
1022
0
      goto done;
1023
1024
0
    if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
1025
0
      continue;
1026
0
    }
1027
1028
0
    err = reftable_writer_add_ref(wr, &ref);
1029
0
    if (err < 0)
1030
0
      goto done;
1031
0
    entries++;
1032
0
  }
1033
0
  reftable_iterator_destroy(&it);
1034
1035
0
  err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
1036
0
  if (err < 0)
1037
0
    goto done;
1038
1039
0
  err = reftable_iterator_seek_log(&it, "");
1040
0
  if (err < 0)
1041
0
    goto done;
1042
1043
0
  while (1) {
1044
0
    err = reftable_iterator_next_log(&it, &log);
1045
0
    if (err > 0) {
1046
0
      err = 0;
1047
0
      break;
1048
0
    }
1049
0
    if (err < 0)
1050
0
      goto done;
1051
0
    if (first == 0 && reftable_log_record_is_deletion(&log)) {
1052
0
      continue;
1053
0
    }
1054
1055
0
    if (config && config->min_update_index > 0 &&
1056
0
        log.update_index < config->min_update_index) {
1057
0
      continue;
1058
0
    }
1059
1060
0
    if (config && config->time > 0 &&
1061
0
        log.value.update.time < config->time) {
1062
0
      continue;
1063
0
    }
1064
1065
0
    err = reftable_writer_add_log(wr, &log);
1066
0
    if (err < 0)
1067
0
      goto done;
1068
0
    entries++;
1069
0
  }
1070
1071
0
done:
1072
0
  reftable_iterator_destroy(&it);
1073
0
  if (mt)
1074
0
    reftable_merged_table_free(mt);
1075
0
  reftable_ref_record_release(&ref);
1076
0
  reftable_log_record_release(&log);
1077
0
  st->stats.entries_written += entries;
1078
0
  return err;
1079
0
}
1080
1081
static int stack_compact_locked(struct reftable_stack *st,
1082
        size_t first, size_t last,
1083
        struct reftable_log_expiry_config *config,
1084
        const struct reftable_write_options *opts,
1085
        struct reftable_tmpfile *tab_file_out)
1086
0
{
1087
0
  struct reftable_buf next_name = REFTABLE_BUF_INIT;
1088
0
  struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
1089
0
  struct reftable_writer *wr = NULL;
1090
0
  struct fd_writer writer=  {
1091
0
    .opts = opts,
1092
0
  };
1093
0
  struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
1094
0
  int err = 0;
1095
1096
0
  err = format_name(&next_name, reftable_table_min_update_index(st->tables[first]),
1097
0
        reftable_table_max_update_index(st->tables[last]));
1098
0
  if (err < 0)
1099
0
    goto done;
1100
1101
0
  err = stack_filename(&tab_file_path, st, next_name.buf);
1102
0
  if (err < 0)
1103
0
    goto done;
1104
1105
0
  err = reftable_buf_addstr(&tab_file_path, ".temp.XXXXXX");
1106
0
  if (err < 0)
1107
0
    goto done;
1108
1109
0
  err = tmpfile_from_pattern(&tab_file, tab_file_path.buf);
1110
0
  if (err < 0)
1111
0
    goto done;
1112
1113
0
  if (opts->default_permissions &&
1114
0
      chmod(tab_file.path, opts->default_permissions) < 0) {
1115
0
    err = REFTABLE_IO_ERROR;
1116
0
    goto done;
1117
0
  }
1118
1119
0
  writer.fd = tab_file.fd;
1120
0
  err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush,
1121
0
          &writer, st->opts.hash_id, opts);
1122
0
  if (err < 0)
1123
0
    goto done;
1124
1125
0
  err = stack_write_compact(st, wr, first, last, config);
1126
0
  if (err < 0)
1127
0
    goto done;
1128
1129
0
  err = reftable_writer_close(wr);
1130
0
  if (err < 0)
1131
0
    goto done;
1132
1133
0
  err = tmpfile_close(&tab_file);
1134
0
  if (err < 0)
1135
0
    goto done;
1136
1137
0
  *tab_file_out = tab_file;
1138
0
  tab_file = REFTABLE_TMPFILE_INIT;
1139
1140
0
done:
1141
0
  tmpfile_delete(&tab_file);
1142
0
  reftable_writer_free(wr);
1143
0
  reftable_buf_release(&next_name);
1144
0
  reftable_buf_release(&tab_file_path);
1145
0
  return err;
1146
0
}
1147
1148
enum stack_compact_range_flags {
1149
  /*
1150
   * Perform a best-effort compaction. That is, even if we cannot lock
1151
   * all tables in the specified range, we will try to compact the
1152
   * remaining slice.
1153
   */
1154
  STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
1155
};
1156
1157
/*
1158
 * Compact all tables in the range `[first, last)` into a single new table.
1159
 *
1160
 * This function returns `0` on success or a code `< 0` on failure. When the
1161
 * stack or any of the tables in the specified range are already locked then
1162
 * this function returns `REFTABLE_LOCK_ERROR`. This is a benign error that
1163
 * callers can either ignore, or they may choose to retry compaction after some
1164
 * amount of time.
1165
 */
1166
static int stack_compact_range(struct reftable_stack *st,
1167
             size_t first, size_t last,
1168
             struct reftable_log_expiry_config *expiry,
1169
             const struct reftable_write_options *opts,
1170
             unsigned int flags)
1171
0
{
1172
0
  struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT;
1173
0
  struct reftable_buf new_table_name = REFTABLE_BUF_INIT;
1174
0
  struct reftable_buf new_table_path = REFTABLE_BUF_INIT;
1175
0
  struct reftable_buf table_name = REFTABLE_BUF_INIT;
1176
0
  struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT;
1177
0
  struct reftable_flock *table_locks = NULL;
1178
0
  struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT;
1179
0
  int is_empty_table = 0, err = 0;
1180
0
  size_t first_to_replace, last_to_replace;
1181
0
  size_t i, nlocks = 0;
1182
0
  char **names = NULL;
1183
1184
0
  if (first > last || (!expiry && first == last)) {
1185
0
    err = 0;
1186
0
    goto done;
1187
0
  }
1188
1189
0
  st->stats.attempts++;
1190
1191
  /*
1192
   * Hold the lock so that we can read "tables.list" and lock all tables
1193
   * which are part of the user-specified range.
1194
   */
1195
0
  err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1196
0
  if (err < 0)
1197
0
    goto done;
1198
1199
  /*
1200
   * Check whether the stack is up-to-date. We unfortunately cannot
1201
   * handle the situation gracefully in case it's _not_ up-to-date
1202
   * because the range of tables that the user has requested us to
1203
   * compact may have been changed. So instead we abort.
1204
   *
1205
   * We could in theory improve the situation by having the caller not
1206
   * pass in a range, but instead the list of tables to compact. If so,
1207
   * we could check that relevant tables still exist. But for now it's
1208
   * good enough to just abort.
1209
   */
1210
0
  err = stack_uptodate(st, 0);
1211
0
  if (err < 0)
1212
0
    goto done;
1213
0
  if (err > 0) {
1214
0
    err = REFTABLE_OUTDATED_ERROR;
1215
0
    goto done;
1216
0
  }
1217
1218
  /*
1219
   * Lock all tables in the user-provided range. This is the slice of our
1220
   * stack which we'll compact.
1221
   *
1222
   * Note that we lock tables in reverse order from last to first. The
1223
   * intent behind this is to allow a newer process to perform best
1224
   * effort compaction of tables that it has added in the case where an
1225
   * older process is still busy compacting tables which are preexisting
1226
   * from the point of view of the newer process.
1227
   */
1228
0
  REFTABLE_ALLOC_ARRAY(table_locks, last - first + 1);
1229
0
  if (!table_locks) {
1230
0
    err = REFTABLE_OUT_OF_MEMORY_ERROR;
1231
0
    goto done;
1232
0
  }
1233
0
  for (i = 0; i < last - first + 1; i++)
1234
0
    table_locks[i] = REFTABLE_FLOCK_INIT;
1235
1236
0
  for (i = last + 1; i > first; i--) {
1237
0
    err = stack_filename(&table_name, st, reftable_table_name(st->tables[i - 1]));
1238
0
    if (err < 0)
1239
0
      goto done;
1240
1241
0
    err = flock_acquire(&table_locks[nlocks], table_name.buf, 0);
1242
0
    if (err < 0) {
1243
      /*
1244
       * When the table is locked already we may do a
1245
       * best-effort compaction and compact only the tables
1246
       * that we have managed to lock so far. This of course
1247
       * requires that we have been able to lock at least two
1248
       * tables, otherwise there would be nothing to compact.
1249
       * In that case, we return a lock error to our caller.
1250
       */
1251
0
      if (err == REFTABLE_LOCK_ERROR && last - (i - 1) >= 2 &&
1252
0
          flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
1253
0
        err = 0;
1254
        /*
1255
         * The subtraction is to offset the index, the
1256
         * addition is to only compact up to the table
1257
         * of the preceding iteration. They obviously
1258
         * cancel each other out, but that may be
1259
         * non-obvious when it was omitted.
1260
         */
1261
0
        first = (i - 1) + 1;
1262
0
        break;
1263
0
      }
1264
1265
0
      goto done;
1266
0
    }
1267
1268
    /*
1269
     * We need to close the lockfiles as we might otherwise easily
1270
     * run into file descriptor exhaustion when we compress a lot
1271
     * of tables.
1272
     */
1273
0
    err = flock_close(&table_locks[nlocks++]);
1274
0
    if (err < 0)
1275
0
      goto done;
1276
0
  }
1277
1278
  /*
1279
   * We have locked all tables in our range and can thus release the
1280
   * "tables.list" lock while compacting the locked tables. This allows
1281
   * concurrent updates to the stack to proceed.
1282
   */
1283
0
  err = flock_release(&tables_list_lock);
1284
0
  if (err < 0) {
1285
0
    err = REFTABLE_IO_ERROR;
1286
0
    goto done;
1287
0
  }
1288
1289
  /*
1290
   * Compact the now-locked tables into a new table. Note that compacting
1291
   * these tables may end up with an empty new table in case tombstones
1292
   * end up cancelling out all refs in that range.
1293
   */
1294
0
  err = stack_compact_locked(st, first, last, expiry, opts, &new_table);
1295
0
  if (err < 0) {
1296
0
    if (err != REFTABLE_EMPTY_TABLE_ERROR)
1297
0
      goto done;
1298
0
    is_empty_table = 1;
1299
0
  }
1300
1301
  /*
1302
   * Now that we have written the new, compacted table we need to re-lock
1303
   * "tables.list". We'll then replace the compacted range of tables with
1304
   * the new table.
1305
   */
1306
0
  err = flock_acquire(&tables_list_lock, st->list_file, opts->lock_timeout_ms);
1307
0
  if (err < 0)
1308
0
    goto done;
1309
1310
0
  if (opts->default_permissions) {
1311
0
    if (chmod(tables_list_lock.path,
1312
0
        opts->default_permissions) < 0) {
1313
0
      err = REFTABLE_IO_ERROR;
1314
0
      goto done;
1315
0
    }
1316
0
  }
1317
1318
  /*
1319
   * As we have unlocked the stack while compacting our slice of tables
1320
   * it may have happened that a concurrently running process has updated
1321
   * the stack while we were compacting. In that case, we need to check
1322
   * whether the tables that we have just compacted still exist in the
1323
   * stack in the exact same order as we have compacted them.
1324
   *
1325
   * If they do exist, then it is fine to continue and replace those
1326
   * tables with our compacted version. If they don't, then we need to
1327
   * abort.
1328
   */
1329
0
  err = stack_uptodate(st, 0);
1330
0
  if (err < 0)
1331
0
    goto done;
1332
0
  if (err > 0) {
1333
0
    ssize_t new_offset = -1;
1334
0
    int fd;
1335
1336
0
    fd = open(st->list_file, O_RDONLY);
1337
0
    if (fd < 0) {
1338
0
      err = REFTABLE_IO_ERROR;
1339
0
      goto done;
1340
0
    }
1341
1342
0
    err = fd_read_lines(fd, &names);
1343
0
    close(fd);
1344
0
    if (err < 0)
1345
0
      goto done;
1346
1347
    /*
1348
     * Search for the offset of the first table that we have
1349
     * compacted in the updated "tables.list" file.
1350
     */
1351
0
    for (size_t i = 0; names[i]; i++) {
1352
0
      if (strcmp(names[i], st->tables[first]->name))
1353
0
        continue;
1354
1355
      /*
1356
       * We have found the first entry. Verify that all the
1357
       * subsequent tables we have compacted still exist in
1358
       * the modified stack in the exact same order as we
1359
       * have compacted them.
1360
       */
1361
0
      for (size_t j = 1; j < last - first + 1; j++) {
1362
0
        const char *old = first + j < st->merged->tables_len ?
1363
0
          st->tables[first + j]->name : NULL;
1364
0
        const char *new = names[i + j];
1365
1366
        /*
1367
         * If some entries are missing or in case the tables
1368
         * have changed then we need to bail out. Again, this
1369
         * shouldn't ever happen because we have locked the
1370
         * tables we are compacting.
1371
         */
1372
0
        if (!old || !new || strcmp(old, new)) {
1373
0
          err = REFTABLE_OUTDATED_ERROR;
1374
0
          goto done;
1375
0
        }
1376
0
      }
1377
1378
0
      new_offset = i;
1379
0
      break;
1380
0
    }
1381
1382
    /*
1383
     * In case we didn't find our compacted tables in the stack we
1384
     * need to bail out. In theory, this should have never happened
1385
     * because we locked the tables we are compacting.
1386
     */
1387
0
    if (new_offset < 0) {
1388
0
      err = REFTABLE_OUTDATED_ERROR;
1389
0
      goto done;
1390
0
    }
1391
1392
    /*
1393
     * We have found the new range that we want to replace, so
1394
     * let's update the range of tables that we want to replace.
1395
     */
1396
0
    first_to_replace = new_offset;
1397
0
    last_to_replace = last + (new_offset - first);
1398
0
  } else {
1399
    /*
1400
     * `fd_read_lines()` uses a `NULL` sentinel to indicate that
1401
     * the array is at its end. As we use `free_names()` to free
1402
     * the array, we need to include this sentinel value here and
1403
     * thus have to allocate `tables_len + 1` many entries.
1404
     */
1405
0
    REFTABLE_CALLOC_ARRAY(names, st->merged->tables_len + 1);
1406
0
    if (!names) {
1407
0
      err = REFTABLE_OUT_OF_MEMORY_ERROR;
1408
0
      goto done;
1409
0
    }
1410
1411
0
    for (size_t i = 0; i < st->merged->tables_len; i++) {
1412
0
      names[i] = reftable_strdup(st->tables[i]->name);
1413
0
      if (!names[i]) {
1414
0
        err = REFTABLE_OUT_OF_MEMORY_ERROR;
1415
0
        goto done;
1416
0
      }
1417
0
    }
1418
0
    first_to_replace = first;
1419
0
    last_to_replace = last;
1420
0
  }
1421
1422
  /*
1423
   * If the resulting compacted table is not empty, then we need to move
1424
   * it into place now.
1425
   */
1426
0
  if (!is_empty_table) {
1427
0
    err = format_name(&new_table_name, st->tables[first]->min_update_index,
1428
0
          st->tables[last]->max_update_index);
1429
0
    if (err < 0)
1430
0
      goto done;
1431
1432
0
    err = reftable_buf_addstr(&new_table_name, ".ref");
1433
0
    if (err < 0)
1434
0
      goto done;
1435
1436
0
    err = stack_filename(&new_table_path, st, new_table_name.buf);
1437
0
    if (err < 0)
1438
0
      goto done;
1439
1440
0
    err = tmpfile_rename(&new_table, new_table_path.buf);
1441
0
    if (err < 0)
1442
0
      goto done;
1443
0
  }
1444
1445
  /*
1446
   * Write the new "tables.list" contents with the compacted table we
1447
   * have just written. In case the compacted table became empty we
1448
   * simply skip writing it.
1449
   */
1450
0
  for (i = 0; i < first_to_replace; i++) {
1451
0
    if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1452
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1453
0
          goto done;
1454
0
  }
1455
0
  if (!is_empty_table) {
1456
0
    if ((err = reftable_buf_addstr(&tables_list_buf, new_table_name.buf)) < 0 ||
1457
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1458
0
      goto done;
1459
0
  }
1460
0
  for (i = last_to_replace + 1; names[i]; i++) {
1461
0
    if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
1462
0
        (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
1463
0
      goto done;
1464
0
  }
1465
1466
0
  err = reftable_write_data(tables_list_lock.fd,
1467
0
          tables_list_buf.buf, tables_list_buf.len);
1468
0
  if (err < 0) {
1469
0
    err = REFTABLE_IO_ERROR;
1470
0
    unlink(new_table_path.buf);
1471
0
    goto done;
1472
0
  }
1473
1474
0
  err = fsync(tables_list_lock.fd);
1475
0
  if (err < 0) {
1476
0
    err = REFTABLE_IO_ERROR;
1477
0
    unlink(new_table_path.buf);
1478
0
    goto done;
1479
0
  }
1480
1481
0
  err = flock_commit(&tables_list_lock);
1482
0
  if (err < 0) {
1483
0
    err = REFTABLE_IO_ERROR;
1484
0
    unlink(new_table_path.buf);
1485
0
    goto done;
1486
0
  }
1487
1488
  /*
1489
   * Reload the stack before deleting the compacted tables. We can only
1490
   * delete the files after we closed them on Windows, so this needs to
1491
   * happen first.
1492
   */
1493
0
  err = reftable_stack_reload_maybe_reuse(st, first < last);
1494
0
  if (err < 0)
1495
0
    goto done;
1496
1497
  /*
1498
   * Delete the old tables. They may still be in use by concurrent
1499
   * readers, so it is expected that unlinking tables may fail.
1500
   */
1501
0
  for (i = 0; i < nlocks; i++) {
1502
0
    struct reftable_flock *table_lock = &table_locks[i];
1503
1504
0
    reftable_buf_reset(&table_name);
1505
0
    err = reftable_buf_add(&table_name, table_lock->path,
1506
0
               strlen(table_lock->path) - strlen(".lock"));
1507
0
    if (err)
1508
0
      continue;
1509
1510
0
    unlink(table_name.buf);
1511
0
  }
1512
1513
0
done:
1514
0
  flock_release(&tables_list_lock);
1515
0
  for (i = 0; table_locks && i < nlocks; i++)
1516
0
    flock_release(&table_locks[i]);
1517
0
  reftable_free(table_locks);
1518
1519
0
  tmpfile_delete(&new_table);
1520
0
  reftable_buf_release(&new_table_name);
1521
0
  reftable_buf_release(&new_table_path);
1522
0
  reftable_buf_release(&tables_list_buf);
1523
0
  reftable_buf_release(&table_name);
1524
0
  free_names(names);
1525
1526
0
  if (err == REFTABLE_LOCK_ERROR)
1527
0
    st->stats.failures++;
1528
1529
0
  return err;
1530
0
}
1531
1532
int reftable_stack_compact_all(struct reftable_stack *st,
1533
             const struct reftable_write_options *opts,
1534
             struct reftable_log_expiry_config *config)
1535
0
{
1536
0
  struct reftable_write_options opts_default = { 0 };
1537
0
  size_t last = st->merged->tables_len ? st->merged->tables_len - 1 : 0;
1538
1539
0
  if (!opts)
1540
0
    opts = &opts_default;
1541
1542
0
  return stack_compact_range(st, 0, last, config, opts, 0);
1543
0
}
1544
1545
static int segment_size(struct segment *s)
1546
0
{
1547
0
  return s->end - s->start;
1548
0
}
1549
1550
struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
1551
            uint8_t factor)
1552
0
{
1553
0
  struct segment seg = { 0 };
1554
0
  uint64_t bytes;
1555
0
  size_t i;
1556
1557
0
  if (!factor)
1558
0
    factor = DEFAULT_GEOMETRIC_FACTOR;
1559
1560
  /*
1561
   * If there are no tables or only a single one then we don't have to
1562
   * compact anything. The sequence is geometric by definition already.
1563
   */
1564
0
  if (n <= 1)
1565
0
    return seg;
1566
1567
  /*
1568
   * Find the ending table of the compaction segment needed to restore the
1569
   * geometric sequence. Note that the segment end is exclusive.
1570
   *
1571
   * To do so, we iterate backwards starting from the most recent table
1572
   * until a valid segment end is found. If the preceding table is smaller
1573
   * than the current table multiplied by the geometric factor (2), the
1574
   * compaction segment end has been identified.
1575
   *
1576
   * Tables after the ending point are not added to the byte count because
1577
   * they are already valid members of the geometric sequence. Due to the
1578
   * properties of a geometric sequence, it is not possible for the sum of
1579
   * these tables to exceed the value of the ending point table.
1580
   *
1581
   * Example table size sequence requiring no compaction:
1582
   *  64, 32, 16, 8, 4, 2, 1
1583
   *
1584
   * Example table size sequence where compaction segment end is set to
1585
   * the last table. Since the segment end is exclusive, the last table is
1586
   * excluded during subsequent compaction and the table with size 3 is
1587
   * the final table included:
1588
   *  64, 32, 16, 8, 4, 3, 1
1589
   */
1590
0
  for (i = n - 1; i > 0; i--) {
1591
0
    if (sizes[i - 1] < sizes[i] * factor) {
1592
0
      seg.end = i + 1;
1593
0
      bytes = sizes[i];
1594
0
      break;
1595
0
    }
1596
0
  }
1597
1598
  /*
1599
   * Find the starting table of the compaction segment by iterating
1600
   * through the remaining tables and keeping track of the accumulated
1601
   * size of all tables seen from the segment end table. The previous
1602
   * table is compared to the accumulated size because the tables from the
1603
   * segment end are merged backwards recursively.
1604
   *
1605
   * Note that we keep iterating even after we have found the first
1606
   * starting point. This is because there may be tables in the stack
1607
   * preceding that first starting point which violate the geometric
1608
   * sequence.
1609
   *
1610
   * Example compaction segment start set to table with size 32:
1611
   *  128, 32, 16, 8, 4, 3, 1
1612
   */
1613
0
  for (; i > 0; i--) {
1614
0
    uint64_t curr = bytes;
1615
0
    bytes += sizes[i - 1];
1616
1617
0
    if (sizes[i - 1] < curr * factor) {
1618
0
      seg.start = i - 1;
1619
0
      seg.bytes = bytes;
1620
0
    }
1621
0
  }
1622
1623
0
  return seg;
1624
0
}
1625
1626
static int stack_segments_for_compaction(struct reftable_stack *st,
1627
           const struct reftable_write_options *opts,
1628
           struct segment *seg)
1629
0
{
1630
0
  int version = (st->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2;
1631
0
  int overhead = header_size(version) - 1;
1632
0
  uint64_t *sizes;
1633
1634
0
  REFTABLE_CALLOC_ARRAY(sizes, st->merged->tables_len);
1635
0
  if (!sizes)
1636
0
    return REFTABLE_OUT_OF_MEMORY_ERROR;
1637
1638
0
  for (size_t i = 0; i < st->merged->tables_len; i++)
1639
0
    sizes[i] = st->tables[i]->size - overhead;
1640
1641
0
  *seg = suggest_compaction_segment(sizes, st->merged->tables_len,
1642
0
            opts->auto_compaction_factor);
1643
0
  reftable_free(sizes);
1644
1645
0
  return 0;
1646
0
}
1647
1648
static int update_segment_if_compaction_required(struct reftable_stack *st,
1649
             const struct reftable_write_options *opts,
1650
             struct segment *seg,
1651
             bool use_geometric,
1652
             bool *required)
1653
0
{
1654
0
  int err;
1655
1656
0
  if (st->merged->tables_len < 2) {
1657
0
    *required = false;
1658
0
    return 0;
1659
0
  }
1660
1661
0
  if (!use_geometric) {
1662
0
    *required = true;
1663
0
    return 0;
1664
0
  }
1665
1666
0
  err = stack_segments_for_compaction(st, opts, seg);
1667
0
  if (err)
1668
0
    return err;
1669
1670
0
  *required = segment_size(seg) > 0;
1671
0
  return 0;
1672
0
}
1673
1674
int reftable_stack_compaction_required(struct reftable_stack *st,
1675
               const struct reftable_write_options *opts,
1676
               bool use_heuristics,
1677
               bool *required)
1678
0
{
1679
0
  struct reftable_write_options opts_default = { 0 };
1680
0
  struct segment seg;
1681
1682
0
  if (!opts)
1683
0
    opts = &opts_default;
1684
1685
0
  return update_segment_if_compaction_required(st, opts, &seg,
1686
0
                 use_heuristics, required);
1687
0
}
1688
1689
int reftable_stack_auto_compact(struct reftable_stack *st,
1690
        const struct reftable_write_options *opts)
1691
0
{
1692
0
  struct reftable_write_options opts_default = { 0 };
1693
0
  struct segment seg;
1694
0
  bool required;
1695
0
  int err;
1696
1697
0
  if (!opts)
1698
0
    opts = &opts_default;
1699
1700
0
  err = update_segment_if_compaction_required(st, opts, &seg, true,
1701
0
                &required);
1702
0
  if (err)
1703
0
    return err;
1704
1705
0
  if (required)
1706
0
    return stack_compact_range(st, seg.start, seg.end - 1,
1707
0
             NULL, opts,
1708
0
             STACK_COMPACT_RANGE_BEST_EFFORT);
1709
1710
0
  return 0;
1711
0
}
1712
1713
struct reftable_compaction_stats *
1714
reftable_stack_compaction_stats(struct reftable_stack *st)
1715
0
{
1716
0
  return &st->stats;
1717
0
}
1718
1719
int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
1720
          struct reftable_ref_record *ref)
1721
0
{
1722
0
  struct reftable_iterator it = { 0 };
1723
0
  int ret;
1724
1725
0
  ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
1726
0
  if (ret)
1727
0
    goto out;
1728
1729
0
  ret = reftable_iterator_seek_ref(&it, refname);
1730
0
  if (ret)
1731
0
    goto out;
1732
1733
0
  ret = reftable_iterator_next_ref(&it, ref);
1734
0
  if (ret)
1735
0
    goto out;
1736
1737
0
  if (strcmp(ref->refname, refname) ||
1738
0
      reftable_ref_record_is_deletion(ref)) {
1739
0
    reftable_ref_record_release(ref);
1740
0
    ret = 1;
1741
0
    goto out;
1742
0
  }
1743
1744
0
out:
1745
0
  reftable_iterator_destroy(&it);
1746
0
  return ret;
1747
0
}
1748
1749
int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
1750
          struct reftable_log_record *log)
1751
0
{
1752
0
  struct reftable_iterator it = {0};
1753
0
  int err;
1754
1755
0
  err = reftable_stack_init_log_iterator(st, &it);
1756
0
  if (err)
1757
0
    goto done;
1758
1759
0
  err = reftable_iterator_seek_log(&it, refname);
1760
0
  if (err)
1761
0
    goto done;
1762
1763
0
  err = reftable_iterator_next_log(&it, log);
1764
0
  if (err)
1765
0
    goto done;
1766
1767
0
  if (strcmp(log->refname, refname) ||
1768
0
      reftable_log_record_is_deletion(log)) {
1769
0
    err = 1;
1770
0
    goto done;
1771
0
  }
1772
1773
0
done:
1774
0
  if (err) {
1775
0
    reftable_log_record_release(log);
1776
0
  }
1777
0
  reftable_iterator_destroy(&it);
1778
0
  return err;
1779
0
}
1780
1781
static int is_table_name(const char *s)
1782
0
{
1783
0
  const char *dot = strrchr(s, '.');
1784
0
  return dot && !strcmp(dot, ".ref");
1785
0
}
1786
1787
static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
1788
             const char *name)
1789
0
{
1790
0
  int err = 0;
1791
0
  uint64_t update_idx = 0;
1792
0
  struct reftable_block_source src = { NULL };
1793
0
  struct reftable_table *table = NULL;
1794
0
  struct reftable_buf table_path = REFTABLE_BUF_INIT;
1795
1796
0
  err = stack_filename(&table_path, st, name);
1797
0
  if (err < 0)
1798
0
    goto done;
1799
1800
0
  err = reftable_block_source_from_file(&src, table_path.buf);
1801
0
  if (err < 0)
1802
0
    goto done;
1803
1804
0
  err = reftable_table_new(&table, &src, name);
1805
0
  if (err < 0)
1806
0
    goto done;
1807
1808
0
  update_idx = reftable_table_max_update_index(table);
1809
0
  reftable_table_decref(table);
1810
1811
0
  if (update_idx <= max) {
1812
0
    unlink(table_path.buf);
1813
0
  }
1814
0
done:
1815
0
  reftable_buf_release(&table_path);
1816
0
}
1817
1818
static int reftable_stack_clean_locked(struct reftable_stack *st)
1819
0
{
1820
0
  uint64_t max = reftable_merged_table_max_update_index(
1821
0
    reftable_stack_merged_table(st));
1822
0
  DIR *dir = opendir(st->reftable_dir);
1823
0
  struct dirent *d = NULL;
1824
0
  if (!dir) {
1825
0
    return REFTABLE_IO_ERROR;
1826
0
  }
1827
1828
0
  while ((d = readdir(dir))) {
1829
0
    int found = 0;
1830
0
    if (!is_table_name(d->d_name))
1831
0
      continue;
1832
1833
0
    for (size_t i = 0; !found && i < st->tables_len; i++)
1834
0
      found = !strcmp(reftable_table_name(st->tables[i]), d->d_name);
1835
0
    if (found)
1836
0
      continue;
1837
1838
0
    remove_maybe_stale_table(st, max, d->d_name);
1839
0
  }
1840
1841
0
  closedir(dir);
1842
0
  return 0;
1843
0
}
1844
1845
int reftable_stack_clean(struct reftable_stack *st)
1846
0
{
1847
0
  struct reftable_addition *add = NULL;
1848
0
  int err = reftable_stack_addition_new(&add, st, NULL);
1849
0
  if (err < 0) {
1850
0
    goto done;
1851
0
  }
1852
1853
0
  err = reftable_stack_clean_locked(st);
1854
1855
0
done:
1856
0
  reftable_addition_destroy(add);
1857
0
  return err;
1858
0
}
1859
1860
enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st)
1861
0
{
1862
0
  return reftable_merged_table_hash_id(st->merged);
1863
0
}