[PATCH v8 0/9] Reftable support git-core

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This adds the reftable library, and hooks it up as a ref backend.

Feedback wanted:

 * spots marked with XXX in the Git source code.
   
   
 * what is a good test strategy? Could we have a CI flavor where we flip the
   default to reftable, and see how it fares?
   
   

v8

 * propagate errors to git.
 * discard empty tables in the stack. 
 * one very basic test (t0031.sh)

v9

 * Added spec as technical doc.
 * Use 4-byte hash ID as API. Storage format for SHA256 is still pending
   discussion.

v10 

 * Serialize 4 byte hash ID to the version-2 format

v11

 * use reftable_ namespace prefix.
 * transaction API to provide locking.
 * reorganized record.{h,c}. More doc in reftable.h
 * support log record deletion.
 * pluggable malloc/free

Han-Wen Nienhuys (8):
  refs.h: clarify reflog iteration order
  create .git/refs in files-backend.c
  refs: document how ref_iterator_advance_fn should handle symrefs
  Add .gitattributes for the reftable/ directory
  reftable: define version 2 of the spec to accomodate SHA256
  reftable: clarify how empty tables should be written
  Add reftable library
  Reftable support for git-core

Jonathan Nieder (1):
  reftable: file format documentation

 Documentation/Makefile                        |    1 +
 Documentation/technical/reftable.txt          | 1080 ++++++++++++++++
 .../technical/repository-version.txt          |    7 +
 Makefile                                      |   24 +-
 builtin/clone.c                               |    5 +-
 builtin/init-db.c                             |   51 +-
 cache.h                                       |    4 +-
 refs.c                                        |   20 +-
 refs.h                                        |    7 +-
 refs/files-backend.c                          |    6 +
 refs/refs-internal.h                          |    6 +
 refs/reftable-backend.c                       | 1002 +++++++++++++++
 reftable/.gitattributes                       |    1 +
 reftable/LICENSE                              |   31 +
 reftable/README.md                            |   11 +
 reftable/VERSION                              |    5 +
 reftable/basics.c                             |  194 +++
 reftable/basics.h                             |   35 +
 reftable/block.c                              |  433 +++++++
 reftable/block.h                              |   76 ++
 reftable/blocksource.h                        |   22 +
 reftable/bytes.c                              |    0
 reftable/config.h                             |    1 +
 reftable/constants.h                          |   21 +
 reftable/dump.c                               |   97 ++
 reftable/file.c                               |   98 ++
 reftable/iter.c                               |  234 ++++
 reftable/iter.h                               |   56 +
 reftable/merged.c                             |  299 +++++
 reftable/merged.h                             |   34 +
 reftable/pq.c                                 |  115 ++
 reftable/pq.h                                 |   34 +
 reftable/reader.c                             |  756 +++++++++++
 reftable/reader.h                             |   60 +
 reftable/record.c                             | 1098 ++++++++++++++++
 reftable/record.h                             |  106 ++
 reftable/reftable.h                           |  520 ++++++++
 reftable/slice.c                              |  219 ++++
 reftable/slice.h                              |   42 +
 reftable/stack.c                              | 1132 +++++++++++++++++
 reftable/stack.h                              |   42 +
 reftable/system.h                             |   53 +
 reftable/tree.c                               |   67 +
 reftable/tree.h                               |   24 +
 reftable/update.sh                            |   14 +
 reftable/writer.c                             |  653 ++++++++++
 reftable/writer.h                             |   45 +
 reftable/zlib-compat.c                        |   92 ++
 repository.c                                  |    2 +
 repository.h                                  |    3 +
 setup.c                                       |   12 +-
 t/t0031-reftable.sh                           |   35 +
 52 files changed, 8954 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/technical/reftable.txt
 create mode 100644 refs/reftable-backend.c
 create mode 100644 reftable/.gitattributes
 create mode 100644 reftable/LICENSE
 create mode 100644 reftable/README.md
 create mode 100644 reftable/VERSION
 create mode 100644 reftable/basics.c
 create mode 100644 reftable/basics.h
 create mode 100644 reftable/block.c
 create mode 100644 reftable/block.h
 create mode 100644 reftable/blocksource.h
 create mode 100644 reftable/bytes.c
 create mode 100644 reftable/config.h
 create mode 100644 reftable/constants.h
 create mode 100644 reftable/dump.c
 create mode 100644 reftable/file.c
 create mode 100644 reftable/iter.c
 create mode 100644 reftable/iter.h
 create mode 100644 reftable/merged.c
 create mode 100644 reftable/merged.h
 create mode 100644 reftable/pq.c
 create mode 100644 reftable/pq.h
 create mode 100644 reftable/reader.c
 create mode 100644 reftable/reader.h
 create mode 100644 reftable/record.c
 create mode 100644 reftable/record.h
 create mode 100644 reftable/reftable.h
 create mode 100644 reftable/slice.c
 create mode 100644 reftable/slice.h
 create mode 100644 reftable/stack.c
 create mode 100644 reftable/stack.h
 create mode 100644 reftable/system.h
 create mode 100644 reftable/tree.c
 create mode 100644 reftable/tree.h
 create mode 100644 reftable/update.sh
 create mode 100644 reftable/writer.c
 create mode 100644 reftable/writer.h
 create mode 100644 reftable/zlib-compat.c
 create mode 100755 t/t0031-reftable.sh


base-commit: 9fadedd637b312089337d73c3ed8447e9f0aa775
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-539%2Fhanwen%2Freftable-v8
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-539/hanwen/reftable-v8
Pull-Request: https://github.com/gitgitgadget/git/pull/539

Range-diff vs v7:

  1:  b1e44bc431e =  1:  05634d26dd5 refs.h: clarify reflog iteration order
  2:  b68488a095e =  2:  8d34e2c5c8b create .git/refs in files-backend.c
  3:  da538ef7421 =  3:  d08f823844d refs: document how ref_iterator_advance_fn should handle symrefs
  -:  ----------- >  4:  ca95b3a371e Add .gitattributes for the reftable/ directory
  4:  aae26814983 =  5:  dfc8b131294 reftable: file format documentation
  -:  ----------- >  6:  45ab5361750 reftable: define version 2 of the spec to accomodate SHA256
  -:  ----------- >  7:  67ee5962e85 reftable: clarify how empty tables should be written
  5:  30ed43a4fdb !  8:  4f9bdd7312b Add reftable library
     @@ -5,21 +5,21 @@
          Reftable is a format for storing the ref database. Its rationale and
          specification is in the preceding commit.
      
     -    Further context and motivation can be found in background reading:
     +    This imports the upstream library as one big commit. For understanding
     +    the code, it is suggested to read the code in the following order:
      
     -    * Original discussion on JGit-dev:  https://www.eclipse.org/lists/jgit-dev/msg03389.html
     +    * The specification under Documentation/technical/reftable.txt
      
     -    * First design discussion on git@vger: https://public-inbox.org/git/CAJo=hJtTp2eA3z9wW9cHo-nA7kK40vVThqh6inXpbCcqfdMP9g@xxxxxxxxxxxxxx/
     +    * reftable.h - the public API
      
     -    * Last design discussion on git@vger: https://public-inbox.org/git/CAJo=hJsZcAM9sipdVr7TMD-FD2V2W6_pvMQ791EGCDsDkQ033w@xxxxxxxxxxxxxx/
     +    * block.{c,h} - reading and writing blocks.
      
     -    * First attempt at implementation: https://public-inbox.org/git/CAP8UFD0PPZSjBnxCA7ez91vBuatcHKQ+JUWvTD1iHcXzPBjPBg@xxxxxxxxxxxxxx/
     +    * writer.{c,h} - writing a complete reftable file.
      
     -    * libgit2 support issue: https://github.com/libgit2/libgit2/issues
     +    * merged.{c,h} and pq.{c,h} - reading a stack of reftables
      
     -    * GitLab support issue: https://gitlab.com/gitlab-org/git/issues/6
     -
     -    * go-git support issue: https://github.com/src-d/go-git/issues/1059
     +    * stack.{c,h} - writing and compacting stacks of reftable on the
     +    filesystem.
      
          Signed-off-by: Han-Wen Nienhuys <hanwen@xxxxxxxxxx>
      
     @@ -82,11 +82,11 @@
       --- /dev/null
       +++ b/reftable/VERSION
      @@
     -+commit ccce3b3eb763e79b23a3b4677d65ecceb4155ba3
     ++commit 920f7413f7a25f308d9a203f584873f6753192ec
      +Author: Han-Wen Nienhuys <hanwen@xxxxxxxxxx>
     -+Date:   Tue Feb 25 20:42:29 2020 +0100
     ++Date:   Wed Apr 1 12:41:41 2020 +0200
      +
     -+    C: rephrase the hash ID API in terms of a uint32_t
     ++    C: remove stray debug printfs
      
       diff --git a/reftable/basics.c b/reftable/basics.c
       new file mode 100644
     @@ -165,10 +165,10 @@
      +		return;
      +	}
      +	while (*p) {
     -+		free(*p);
     ++		reftable_free(*p);
      +		p++;
      +	}
     -+	free(a);
     ++	reftable_free(a);
      +}
      +
      +int names_length(char **names)
     @@ -201,8 +201,8 @@
      +		if (p < next) {
      +			if (names_len == names_cap) {
      +				names_cap = 2 * names_cap + 1;
     -+				names = realloc(names,
     -+						names_cap * sizeof(char *));
     ++				names = reftable_realloc(
     ++					names, names_cap * sizeof(char *));
      +			}
      +			names[names_len++] = xstrdup(p);
      +		}
     @@ -211,7 +211,7 @@
      +
      +	if (names_len == names_cap) {
      +		names_cap = 2 * names_cap + 1;
     -+		names = realloc(names, names_cap * sizeof(char *));
     ++		names = reftable_realloc(names, names_cap * sizeof(char *));
      +	}
      +
      +	names[names_len] = NULL;
     @@ -232,7 +232,7 @@
      +	return *a == *b;
      +}
      +
     -+const char *error_str(int err)
     ++const char *reftable_error_str(int err)
      +{
      +	switch (err) {
      +	case IO_ERROR:
     @@ -252,6 +252,40 @@
      +	default:
      +		return "unknown error code";
      +	}
     ++}
     ++
     ++void *(*reftable_malloc_ptr)(size_t sz) = &malloc;
     ++void *(*reftable_realloc_ptr)(void *, size_t) = &realloc;
     ++void (*reftable_free_ptr)(void *) = &free;
     ++
     ++void *reftable_malloc(size_t sz)
     ++{
     ++	return (*reftable_malloc_ptr)(sz);
     ++}
     ++
     ++void *reftable_realloc(void *p, size_t sz)
     ++{
     ++	return (*reftable_realloc_ptr)(p, sz);
     ++}
     ++
     ++void reftable_free(void *p)
     ++{
     ++	reftable_free_ptr(p);
     ++}
     ++
     ++void *reftable_calloc(size_t sz)
     ++{
     ++	void *p = reftable_malloc(sz);
     ++	memset(p, 0, sz);
     ++	return p;
     ++}
     ++
     ++void reftable_set_alloc(void *(*malloc)(size_t),
     ++			void *(*realloc)(void *, size_t), void (*free)(void *))
     ++{
     ++	reftable_malloc_ptr = malloc;
     ++	reftable_realloc_ptr = realloc;
     ++	reftable_free_ptr = free;
      +}
      
       diff --git a/reftable/basics.h b/reftable/basics.h
     @@ -288,6 +322,11 @@
      +int names_equal(char **a, char **b);
      +int names_length(char **names);
      +
     ++void *reftable_malloc(size_t sz);
     ++void *reftable_realloc(void *p, size_t sz);
     ++void reftable_free(void *p);
     ++void *reftable_calloc(size_t sz);
     ++
      +#endif
      
       diff --git a/reftable/block.c b/reftable/block.c
     @@ -313,10 +352,32 @@
      +#include "reftable.h"
      +#include "zlib.h"
      +
     -+int block_writer_register_restart(struct block_writer *w, int n, bool restart,
     -+				  struct slice key);
     ++int header_size(int version)
     ++{
     ++	switch (version) {
     ++	case 1:
     ++		return 24;
     ++	case 2:
     ++		return 28;
     ++	}
     ++	abort();
     ++}
     ++
     ++int footer_size(int version)
     ++{
     ++	switch (version) {
     ++	case 1:
     ++		return 68;
     ++	case 2:
     ++		return 72;
     ++	}
     ++	abort();
     ++}
     ++
     ++int block_writer_register_restart(struct reftable_block_writer *w, int n,
     ++				  bool restart, struct slice key);
      +
     -+void block_writer_init(struct block_writer *bw, byte typ, byte *buf,
     ++void block_writer_init(struct reftable_block_writer *bw, byte typ, byte *buf,
      +		       uint32_t block_size, uint32_t header_off, int hash_size)
      +{
      +	bw->buf = buf;
     @@ -329,14 +390,14 @@
      +	bw->entries = 0;
      +}
      +
     -+byte block_writer_type(struct block_writer *bw)
     ++byte block_writer_type(struct reftable_block_writer *bw)
      +{
      +	return bw->buf[bw->header_off];
      +}
      +
      +/* adds the record to the block. Returns -1 if it does not fit, 0 on
      +   success */
     -+int block_writer_add(struct block_writer *w, struct record rec)
     ++int block_writer_add(struct reftable_block_writer *w, struct record rec)
      +{
      +	struct slice empty = { 0 };
      +	struct slice last = w->entries % w->restart_interval == 0 ? empty :
     @@ -357,32 +418,29 @@
      +	if (n < 0) {
      +		goto err;
      +	}
     -+	out.buf += n;
     -+	out.len -= n;
     ++	slice_consume(&out, n);
      +
      +	n = record_encode(rec, out, w->hash_size);
      +	if (n < 0) {
      +		goto err;
      +	}
     -+
     -+	out.buf += n;
     -+	out.len -= n;
     ++	slice_consume(&out, n);
      +
      +	if (block_writer_register_restart(w, start.len - out.len, restart,
      +					  key) < 0) {
      +		goto err;
      +	}
      +
     -+	free(slice_yield(&key));
     ++	reftable_free(slice_yield(&key));
      +	return 0;
      +
      +err:
     -+	free(slice_yield(&key));
     ++	reftable_free(slice_yield(&key));
      +	return -1;
      +}
      +
     -+int block_writer_register_restart(struct block_writer *w, int n, bool restart,
     -+				  struct slice key)
     ++int block_writer_register_restart(struct reftable_block_writer *w, int n,
     ++				  bool restart, struct slice key)
      +{
      +	int rlen = w->restart_len;
      +	if (rlen >= MAX_RESTARTS) {
     @@ -398,7 +456,7 @@
      +	if (restart) {
      +		if (w->restart_len == w->restart_cap) {
      +			w->restart_cap = w->restart_cap * 2 + 1;
     -+			w->restarts = realloc(
     ++			w->restarts = reftable_realloc(
      +				w->restarts, sizeof(uint32_t) * w->restart_cap);
      +		}
      +
     @@ -411,7 +469,7 @@
      +	return 0;
      +}
      +
     -+int block_writer_finish(struct block_writer *w)
     ++int block_writer_finish(struct reftable_block_writer *w)
      +{
      +	int i = 0;
      +	for (i = 0; i < w->restart_len; i++) {
     @@ -442,7 +500,7 @@
      +			}
      +
      +			if (Z_OK != zresult) {
     -+				free(slice_yield(&compressed));
     ++				reftable_free(slice_yield(&compressed));
      +				return ZLIB_ERROR;
      +			}
      +
     @@ -455,14 +513,14 @@
      +	return w->next;
      +}
      +
     -+byte block_reader_type(struct block_reader *r)
     ++byte block_reader_type(struct reftable_block_reader *r)
      +{
      +	return r->block.data[r->header_off];
      +}
      +
     -+int block_reader_init(struct block_reader *br, struct block *block,
     -+		      uint32_t header_off, uint32_t table_block_size,
     -+		      int hash_size)
     ++int block_reader_init(struct reftable_block_reader *br,
     ++		      struct reftable_block *block, uint32_t header_off,
     ++		      uint32_t table_block_size, int hash_size)
      +{
      +	uint32_t full_block_size = table_block_size;
      +	byte typ = block->data[header_off];
     @@ -485,7 +543,7 @@
      +				    uncompressed.buf + block_header_skip,
      +				    &dst_len, block->data + block_header_skip,
      +				    &src_len)) {
     -+			free(slice_yield(&uncompressed));
     ++			reftable_free(slice_yield(&uncompressed));
      +			return ZLIB_ERROR;
      +		}
      +
     @@ -526,12 +584,14 @@
      +	return 0;
      +}
      +
     -+static uint32_t block_reader_restart_offset(struct block_reader *br, int i)
     ++static uint32_t block_reader_restart_offset(struct reftable_block_reader *br,
     ++					    int i)
      +{
      +	return get_be24(br->restart_bytes + 3 * i);
      +}
      +
     -+void block_reader_start(struct block_reader *br, struct block_iter *it)
     ++void block_reader_start(struct reftable_block_reader *br,
     ++			struct reftable_block_iter *it)
      +{
      +	it->br = br;
      +	slice_resize(&it->last_key, 0);
     @@ -541,7 +601,7 @@
      +struct restart_find_args {
      +	int error;
      +	struct slice key;
     -+	struct block_reader *r;
     ++	struct reftable_block_reader *r;
      +};
      +
      +static int restart_key_less(int idx, void *args)
     @@ -566,12 +626,13 @@
      +
      +	{
      +		int result = slice_compare(a->key, rkey);
     -+		free(slice_yield(&rkey));
     ++		reftable_free(slice_yield(&rkey));
      +		return result;
      +	}
      +}
      +
     -+void block_iter_copy_from(struct block_iter *dest, struct block_iter *src)
     ++void block_iter_copy_from(struct reftable_block_iter *dest,
     ++			  struct reftable_block_iter *src)
      +{
      +	dest->br = src->br;
      +	dest->next_off = src->next_off;
     @@ -579,7 +640,7 @@
      +}
      +
      +/* return < 0 for error, 0 for OK, > 0 for EOF. */
     -+int block_iter_next(struct block_iter *it, struct record rec)
     ++int block_iter_next(struct reftable_block_iter *it, struct record rec)
      +{
      +	if (it->next_off >= it->br->block_len) {
      +		return 1;
     @@ -598,23 +659,21 @@
      +			return -1;
      +		}
      +
     -+		in.buf += n;
     -+		in.len -= n;
     ++		slice_consume(&in, n);
      +		n = record_decode(rec, key, extra, in, it->br->hash_size);
      +		if (n < 0) {
      +			return -1;
      +		}
     -+		in.buf += n;
     -+		in.len -= n;
     ++		slice_consume(&in, n);
      +
      +		slice_copy(&it->last_key, key);
      +		it->next_off += start.len - in.len;
     -+		free(slice_yield(&key));
     ++		reftable_free(slice_yield(&key));
      +		return 0;
      +	}
      +}
      +
     -+int block_reader_first_key(struct block_reader *br, struct slice *key)
     ++int block_reader_first_key(struct reftable_block_reader *br, struct slice *key)
      +{
      +	struct slice empty = { 0 };
      +	int off = br->header_off + 4;
     @@ -631,18 +690,18 @@
      +	return 0;
      +}
      +
     -+int block_iter_seek(struct block_iter *it, struct slice want)
     ++int block_iter_seek(struct reftable_block_iter *it, struct slice want)
      +{
      +	return block_reader_seek(it->br, it, want);
      +}
      +
     -+void block_iter_close(struct block_iter *it)
     ++void block_iter_close(struct reftable_block_iter *it)
      +{
     -+	free(slice_yield(&it->last_key));
     ++	reftable_free(slice_yield(&it->last_key));
      +}
      +
     -+int block_reader_seek(struct block_reader *br, struct block_iter *it,
     -+		      struct slice want)
     ++int block_reader_seek(struct reftable_block_reader *br,
     ++		      struct reftable_block_iter *it, struct slice want)
      +{
      +	struct restart_find_args args = {
      +		.key = want,
     @@ -667,7 +726,7 @@
      +		struct slice key = { 0 };
      +		int result = 0;
      +		int err = 0;
     -+		struct block_iter next = { 0 };
     ++		struct reftable_block_iter next = { 0 };
      +		while (true) {
      +			block_iter_copy_from(&next, it);
      +
     @@ -687,25 +746,25 @@
      +		}
      +
      +	exit:
     -+		free(slice_yield(&key));
     -+		free(slice_yield(&next.last_key));
     ++		reftable_free(slice_yield(&key));
     ++		reftable_free(slice_yield(&next.last_key));
      +		record_clear(rec);
     -+		free(record_yield(&rec));
     ++		reftable_free(record_yield(&rec));
      +
      +		return result;
      +	}
      +}
      +
     -+void block_writer_reset(struct block_writer *bw)
     ++void block_writer_reset(struct reftable_block_writer *bw)
      +{
      +	bw->restart_len = 0;
      +	bw->last_key.len = 0;
      +}
      +
     -+void block_writer_clear(struct block_writer *bw)
     ++void block_writer_clear(struct reftable_block_writer *bw)
      +{
      +	FREE_AND_NULL(bw->restarts);
     -+	free(slice_yield(&bw->last_key));
     ++	reftable_free(slice_yield(&bw->last_key));
      +	/* the block is not owned. */
      +}
      
     @@ -729,7 +788,7 @@
      +#include "record.h"
      +#include "reftable.h"
      +
     -+struct block_writer {
     ++struct reftable_block_writer {
      +	byte *buf;
      +	uint32_t block_size;
      +	uint32_t header_off;
     @@ -744,17 +803,17 @@
      +	int entries;
      +};
      +
     -+void block_writer_init(struct block_writer *bw, byte typ, byte *buf,
     ++void block_writer_init(struct reftable_block_writer *bw, byte typ, byte *buf,
      +		       uint32_t block_size, uint32_t header_off, int hash_size);
     -+byte block_writer_type(struct block_writer *bw);
     -+int block_writer_add(struct block_writer *w, struct record rec);
     -+int block_writer_finish(struct block_writer *w);
     -+void block_writer_reset(struct block_writer *bw);
     -+void block_writer_clear(struct block_writer *bw);
     ++byte block_writer_type(struct reftable_block_writer *bw);
     ++int block_writer_add(struct reftable_block_writer *w, struct record rec);
     ++int block_writer_finish(struct reftable_block_writer *w);
     ++void block_writer_reset(struct reftable_block_writer *bw);
     ++void block_writer_clear(struct reftable_block_writer *bw);
      +
     -+struct block_reader {
     ++struct reftable_block_reader {
      +	uint32_t header_off;
     -+	struct block block;
     ++	struct reftable_block block;
      +	int hash_size;
      +
      +	/* size of the data, excluding restart data. */
     @@ -764,25 +823,30 @@
      +	uint16_t restart_count;
      +};
      +
     -+struct block_iter {
     ++struct reftable_block_iter {
      +	uint32_t next_off;
     -+	struct block_reader *br;
     ++	struct reftable_block_reader *br;
      +	struct slice last_key;
      +};
      +
     -+int block_reader_init(struct block_reader *br, struct block *bl,
     -+		      uint32_t header_off, uint32_t table_block_size,
     -+		      int hash_size);
     -+void block_reader_start(struct block_reader *br, struct block_iter *it);
     -+int block_reader_seek(struct block_reader *br, struct block_iter *it,
     -+		      struct slice want);
     -+byte block_reader_type(struct block_reader *r);
     -+int block_reader_first_key(struct block_reader *br, struct slice *key);
     -+
     -+void block_iter_copy_from(struct block_iter *dest, struct block_iter *src);
     -+int block_iter_next(struct block_iter *it, struct record rec);
     -+int block_iter_seek(struct block_iter *it, struct slice want);
     -+void block_iter_close(struct block_iter *it);
     ++int block_reader_init(struct reftable_block_reader *br,
     ++		      struct reftable_block *bl, uint32_t header_off,
     ++		      uint32_t table_block_size, int hash_size);
     ++void block_reader_start(struct reftable_block_reader *br,
     ++			struct reftable_block_iter *it);
     ++int block_reader_seek(struct reftable_block_reader *br,
     ++		      struct reftable_block_iter *it, struct slice want);
     ++byte block_reader_type(struct reftable_block_reader *r);
     ++int block_reader_first_key(struct reftable_block_reader *br, struct slice *key);
     ++
     ++void block_iter_copy_from(struct reftable_block_iter *dest,
     ++			  struct reftable_block_iter *src);
     ++int block_iter_next(struct reftable_block_iter *it, struct record rec);
     ++int block_iter_seek(struct reftable_block_iter *it, struct slice want);
     ++void block_iter_close(struct reftable_block_iter *it);
     ++
     ++int header_size(int version);
     ++int footer_size(int version);
      +
      +#endif
      
     @@ -804,11 +868,13 @@
      +
      +#include "reftable.h"
      +
     -+uint64_t block_source_size(struct block_source source);
     -+int block_source_read_block(struct block_source source, struct block *dest,
     -+			    uint64_t off, uint32_t size);
     -+void block_source_return_block(struct block_source source, struct block *ret);
     -+void block_source_close(struct block_source source);
     ++uint64_t block_source_size(struct reftable_block_source source);
     ++int block_source_read_block(struct reftable_block_source source,
     ++			    struct reftable_block *dest, uint64_t off,
     ++			    uint32_t size);
     ++void block_source_return_block(struct reftable_block_source source,
     ++			       struct reftable_block *ret);
     ++void block_source_close(struct reftable_block_source source);
      +
      +#endif
      
     @@ -838,10 +904,6 @@
      +#ifndef CONSTANTS_H
      +#define CONSTANTS_H
      +
     -+#define VERSION 1
     -+#define HEADER_SIZE 24
     -+#define FOOTER_SIZE 68
     -+
      +#define BLOCK_TYPE_LOG 'g'
      +#define BLOCK_TYPE_INDEX 'i'
      +#define BLOCK_TYPE_REF 'r'
     @@ -987,10 +1049,10 @@
      +	return ((struct file_block_source *)b)->size;
      +}
      +
     -+static void file_return_block(void *b, struct block *dest)
     ++static void file_return_block(void *b, struct reftable_block *dest)
      +{
      +	memset(dest->data, 0xff, dest->len);
     -+	free(dest->data);
     ++	reftable_free(dest->data);
      +}
      +
      +static void file_close(void *b)
     @@ -1001,15 +1063,15 @@
      +		((struct file_block_source *)b)->fd = 0;
      +	}
      +
     -+	free(b);
     ++	reftable_free(b);
      +}
      +
     -+static int file_read_block(void *v, struct block *dest, uint64_t off,
     ++static int file_read_block(void *v, struct reftable_block *dest, uint64_t off,
      +			   uint32_t size)
      +{
      +	struct file_block_source *b = (struct file_block_source *)v;
      +	assert(off + size <= b->size);
     -+	dest->data = malloc(size);
     ++	dest->data = reftable_malloc(size);
      +	if (pread(b->fd, dest->data, size, off) != size) {
      +		return -1;
      +	}
     @@ -1017,14 +1079,15 @@
      +	return size;
      +}
      +
     -+struct block_source_vtable file_vtable = {
     ++struct reftable_block_source_vtable file_vtable = {
      +	.size = &file_size,
      +	.read_block = &file_read_block,
      +	.return_block = &file_return_block,
      +	.close = &file_close,
      +};
      +
     -+int block_source_from_file(struct block_source *bs, const char *name)
     ++int reftable_block_source_from_file(struct reftable_block_source *bs,
     ++				    const char *name)
      +{
      +	struct stat st = { 0 };
      +	int err = 0;
     @@ -1043,7 +1106,7 @@
      +
      +	{
      +		struct file_block_source *p =
     -+			calloc(sizeof(struct file_block_source), 1);
     ++			reftable_calloc(sizeof(struct file_block_source));
      +		p->size = st.st_size;
      +		p->fd = fd;
      +
     @@ -1053,7 +1116,7 @@
      +	return 0;
      +}
      +
     -+int fd_writer(void *arg, byte *data, int sz)
     ++int reftable_fd_write(void *arg, byte *data, int sz)
      +{
      +	int *fdp = (int *)arg;
      +	return write(*fdp, data, sz);
     @@ -1081,7 +1144,7 @@
      +#include "reader.h"
      +#include "reftable.h"
      +
     -+bool iterator_is_null(struct iterator it)
     ++bool iterator_is_null(struct reftable_iterator it)
      +{
      +	return it.ops == NULL;
      +}
     @@ -1095,23 +1158,23 @@
      +{
      +}
      +
     -+struct iterator_vtable empty_vtable = {
     ++struct reftable_iterator_vtable empty_vtable = {
      +	.next = &empty_iterator_next,
      +	.close = &empty_iterator_close,
      +};
      +
     -+void iterator_set_empty(struct iterator *it)
     ++void iterator_set_empty(struct reftable_iterator *it)
      +{
      +	it->iter_arg = NULL;
      +	it->ops = &empty_vtable;
      +}
      +
     -+int iterator_next(struct iterator it, struct record rec)
     ++int iterator_next(struct reftable_iterator it, struct record rec)
      +{
      +	return it.ops->next(it.iter_arg, rec);
      +}
      +
     -+void iterator_destroy(struct iterator *it)
     ++void reftable_iterator_destroy(struct reftable_iterator *it)
      +{
      +	if (it->ops == NULL) {
      +		return;
     @@ -1121,14 +1184,16 @@
      +	FREE_AND_NULL(it->iter_arg);
      +}
      +
     -+int iterator_next_ref(struct iterator it, struct ref_record *ref)
     ++int reftable_iterator_next_ref(struct reftable_iterator it,
     ++			       struct reftable_ref_record *ref)
      +{
      +	struct record rec = { 0 };
      +	record_from_ref(&rec, ref);
      +	return iterator_next(it, rec);
      +}
      +
     -+int iterator_next_log(struct iterator it, struct log_record *log)
     ++int reftable_iterator_next_log(struct reftable_iterator it,
     ++			       struct reftable_log_record *log)
      +{
      +	struct record rec = { 0 };
      +	record_from_log(&rec, log);
     @@ -1139,31 +1204,33 @@
      +{
      +	struct filtering_ref_iterator *fri =
      +		(struct filtering_ref_iterator *)iter_arg;
     -+	free(slice_yield(&fri->oid));
     -+	iterator_destroy(&fri->it);
     ++	reftable_free(slice_yield(&fri->oid));
     ++	reftable_iterator_destroy(&fri->it);
      +}
      +
      +static int filtering_ref_iterator_next(void *iter_arg, struct record rec)
      +{
      +	struct filtering_ref_iterator *fri =
      +		(struct filtering_ref_iterator *)iter_arg;
     -+	struct ref_record *ref = (struct ref_record *)rec.data;
     ++	struct reftable_ref_record *ref =
     ++		(struct reftable_ref_record *)rec.data;
      +
      +	while (true) {
     -+		int err = iterator_next_ref(fri->it, ref);
     ++		int err = reftable_iterator_next_ref(fri->it, ref);
      +		if (err != 0) {
      +			return err;
      +		}
      +
      +		if (fri->double_check) {
     -+			struct iterator it = { 0 };
     ++			struct reftable_iterator it = { 0 };
      +
     -+			int err = reader_seek_ref(fri->r, &it, ref->ref_name);
     ++			int err = reftable_reader_seek_ref(fri->r, &it,
     ++							   ref->ref_name);
      +			if (err == 0) {
     -+				err = iterator_next_ref(it, ref);
     ++				err = reftable_iterator_next_ref(it, ref);
      +			}
      +
     -+			iterator_destroy(&it);
     ++			reftable_iterator_destroy(&it);
      +
      +			if (err < 0) {
      +				return err;
     @@ -1183,12 +1250,12 @@
      +	}
      +}
      +
     -+struct iterator_vtable filtering_ref_iterator_vtable = {
     ++struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
      +	.next = &filtering_ref_iterator_next,
      +	.close = &filtering_ref_iterator_close,
      +};
      +
     -+void iterator_from_filtering_ref_iterator(struct iterator *it,
     ++void iterator_from_filtering_ref_iterator(struct reftable_iterator *it,
      +					  struct filtering_ref_iterator *fri)
      +{
      +	it->iter_arg = fri;
     @@ -1200,7 +1267,7 @@
      +	struct indexed_table_ref_iter *it = (struct indexed_table_ref_iter *)p;
      +	block_iter_close(&it->cur);
      +	reader_return_block(it->r, &it->block_reader.block);
     -+	free(slice_yield(&it->oid));
     ++	reftable_free(slice_yield(&it->oid));
      +}
      +
      +static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
     @@ -1231,7 +1298,8 @@
      +static int indexed_table_ref_iter_next(void *p, struct record rec)
      +{
      +	struct indexed_table_ref_iter *it = (struct indexed_table_ref_iter *)p;
     -+	struct ref_record *ref = (struct ref_record *)rec.data;
     ++	struct reftable_ref_record *ref =
     ++		(struct reftable_ref_record *)rec.data;
      +
      +	while (true) {
      +		int err = block_iter_next(&it->cur, rec);
     @@ -1259,11 +1327,11 @@
      +}
      +
      +int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
     -+			       struct reader *r, byte *oid, int oid_len,
     -+			       uint64_t *offsets, int offset_len)
     ++			       struct reftable_reader *r, byte *oid,
     ++			       int oid_len, uint64_t *offsets, int offset_len)
      +{
      +	struct indexed_table_ref_iter *itr =
     -+		calloc(sizeof(struct indexed_table_ref_iter), 1);
     ++		reftable_calloc(sizeof(struct indexed_table_ref_iter));
      +	int err = 0;
      +
      +	itr->r = r;
     @@ -1275,19 +1343,19 @@
      +
      +	err = indexed_table_ref_iter_next_block(itr);
      +	if (err < 0) {
     -+		free(itr);
     ++		reftable_free(itr);
      +	} else {
      +		*dest = itr;
      +	}
      +	return err;
      +}
      +
     -+struct iterator_vtable indexed_table_ref_iter_vtable = {
     ++struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
      +	.next = &indexed_table_ref_iter_next,
      +	.close = &indexed_table_ref_iter_close,
      +};
      +
     -+void iterator_from_indexed_table_ref_iter(struct iterator *it,
     ++void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
      +					  struct indexed_table_ref_iter *itr)
      +{
      +	it->iter_arg = itr;
     @@ -1314,27 +1382,27 @@
      +#include "record.h"
      +#include "slice.h"
      +
     -+struct iterator_vtable {
     ++struct reftable_iterator_vtable {
      +	int (*next)(void *iter_arg, struct record rec);
      +	void (*close)(void *iter_arg);
      +};
      +
     -+void iterator_set_empty(struct iterator *it);
     -+int iterator_next(struct iterator it, struct record rec);
     -+bool iterator_is_null(struct iterator it);
     ++void iterator_set_empty(struct reftable_iterator *it);
     ++int iterator_next(struct reftable_iterator it, struct record rec);
     ++bool iterator_is_null(struct reftable_iterator it);
      +
      +struct filtering_ref_iterator {
      +	bool double_check;
     -+	struct reader *r;
     ++	struct reftable_reader *r;
      +	struct slice oid;
     -+	struct iterator it;
     ++	struct reftable_iterator it;
      +};
      +
     -+void iterator_from_filtering_ref_iterator(struct iterator *,
     ++void iterator_from_filtering_ref_iterator(struct reftable_iterator *,
      +					  struct filtering_ref_iterator *);
      +
      +struct indexed_table_ref_iter {
     -+	struct reader *r;
     ++	struct reftable_reader *r;
      +	struct slice oid;
      +
      +	/* mutable */
     @@ -1343,16 +1411,16 @@
      +	/* Points to the next offset to read. */
      +	int offset_idx;
      +	int offset_len;
     -+	struct block_reader block_reader;
     -+	struct block_iter cur;
     ++	struct reftable_block_reader block_reader;
     ++	struct reftable_block_iter cur;
      +	bool finished;
      +};
      +
     -+void iterator_from_indexed_table_ref_iter(struct iterator *it,
     ++void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
      +					  struct indexed_table_ref_iter *itr);
      +int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
     -+			       struct reader *r, byte *oid, int oid_len,
     -+			       uint64_t *offsets, int offset_len);
     ++			       struct reftable_reader *r, byte *oid,
     ++			       int oid_len, uint64_t *offsets, int offset_len);
      +
      +#endif
      
     @@ -1389,9 +1457,9 @@
      +		}
      +
      +		if (err > 0) {
     -+			iterator_destroy(&mi->stack[i]);
     ++			reftable_iterator_destroy(&mi->stack[i]);
      +			record_clear(rec);
     -+			free(record_yield(&rec));
     ++			reftable_free(record_yield(&rec));
      +		} else {
      +			struct pq_entry e = {
      +				.rec = rec,
     @@ -1410,9 +1478,9 @@
      +	int i = 0;
      +	merged_iter_pqueue_clear(&mi->pq);
      +	for (i = 0; i < mi->stack_len; i++) {
     -+		iterator_destroy(&mi->stack[i]);
     ++		reftable_iterator_destroy(&mi->stack[i]);
      +	}
     -+	free(mi->stack);
     ++	reftable_free(mi->stack);
      +}
      +
      +static int merged_iter_advance_subiter(struct merged_iter *mi, int idx)
     @@ -1433,9 +1501,9 @@
      +		}
      +
      +		if (err > 0) {
     -+			iterator_destroy(&mi->stack[idx]);
     ++			reftable_iterator_destroy(&mi->stack[idx]);
      +			record_clear(rec);
     -+			free(record_yield(&rec));
     ++			reftable_free(record_yield(&rec));
      +			return 0;
      +		}
      +
     @@ -1462,7 +1530,7 @@
      +		record_key(top.rec, &k);
      +
      +		cmp = slice_compare(k, entry_key);
     -+		free(slice_yield(&k));
     ++		reftable_free(slice_yield(&k));
      +
      +		if (cmp > 0) {
      +			break;
     @@ -1474,13 +1542,13 @@
      +			return err;
      +		}
      +		record_clear(top.rec);
     -+		free(record_yield(&top.rec));
     ++		reftable_free(record_yield(&top.rec));
      +	}
      +
      +	record_copy_from(rec, entry.rec, hash_size(mi->hash_id));
      +	record_clear(entry.rec);
     -+	free(record_yield(&entry.rec));
     -+	free(slice_yield(&entry_key));
     ++	reftable_free(record_yield(&entry.rec));
     ++	reftable_free(slice_yield(&entry_key));
      +	return 0;
      +}
      +
     @@ -1494,41 +1562,42 @@
      +	return merged_iter_next(mi, rec);
      +}
      +
     -+struct iterator_vtable merged_iter_vtable = {
     ++struct reftable_iterator_vtable merged_iter_vtable = {
      +	.next = &merged_iter_next_void,
      +	.close = &merged_iter_close,
      +};
      +
     -+static void iterator_from_merged_iter(struct iterator *it,
     ++static void iterator_from_merged_iter(struct reftable_iterator *it,
      +				      struct merged_iter *mi)
      +{
      +	it->iter_arg = mi;
      +	it->ops = &merged_iter_vtable;
      +}
      +
     -+int new_merged_table(struct merged_table **dest, struct reader **stack, int n,
     -+		     uint32_t hash_id)
     ++int reftable_new_merged_table(struct reftable_merged_table **dest,
     ++			      struct reftable_reader **stack, int n,
     ++			      uint32_t hash_id)
      +{
      +	uint64_t last_max = 0;
      +	uint64_t first_min = 0;
      +	int i = 0;
      +	for (i = 0; i < n; i++) {
     -+		struct reader *r = stack[i];
     ++		struct reftable_reader *r = stack[i];
      +		if (r->hash_id != hash_id) {
      +			return FORMAT_ERROR;
      +		}
     -+		if (i > 0 && last_max >= reader_min_update_index(r)) {
     ++		if (i > 0 && last_max >= reftable_reader_min_update_index(r)) {
      +			return FORMAT_ERROR;
      +		}
      +		if (i == 0) {
     -+			first_min = reader_min_update_index(r);
     ++			first_min = reftable_reader_min_update_index(r);
      +		}
      +
     -+		last_max = reader_max_update_index(r);
     ++		last_max = reftable_reader_max_update_index(r);
      +	}
      +
      +	{
     -+		struct merged_table m = {
     ++		struct reftable_merged_table m = {
      +			.stack = stack,
      +			.stack_len = n,
      +			.min = first_min,
     @@ -1536,52 +1605,56 @@
      +			.hash_id = hash_id,
      +		};
      +
     -+		*dest = calloc(sizeof(struct merged_table), 1);
     ++		*dest = reftable_calloc(sizeof(struct reftable_merged_table));
      +		**dest = m;
      +	}
      +	return 0;
      +}
      +
     -+void merged_table_close(struct merged_table *mt)
     ++void reftable_merged_table_close(struct reftable_merged_table *mt)
      +{
      +	int i = 0;
      +	for (i = 0; i < mt->stack_len; i++) {
     -+		reader_free(mt->stack[i]);
     ++		reftable_reader_free(mt->stack[i]);
      +	}
      +	FREE_AND_NULL(mt->stack);
      +	mt->stack_len = 0;
      +}
      +
      +/* clears the list of subtable, without affecting the readers themselves. */
     -+void merged_table_clear(struct merged_table *mt)
     ++void merged_table_clear(struct reftable_merged_table *mt)
      +{
      +	FREE_AND_NULL(mt->stack);
      +	mt->stack_len = 0;
      +}
      +
     -+void merged_table_free(struct merged_table *mt)
     ++void reftable_merged_table_free(struct reftable_merged_table *mt)
      +{
      +	if (mt == NULL) {
      +		return;
      +	}
      +	merged_table_clear(mt);
     -+	free(mt);
     ++	reftable_free(mt);
      +}
      +
     -+uint64_t merged_max_update_index(struct merged_table *mt)
     ++uint64_t
     ++reftable_merged_table_max_update_index(struct reftable_merged_table *mt)
      +{
      +	return mt->max;
      +}
      +
     -+uint64_t merged_min_update_index(struct merged_table *mt)
     ++uint64_t
     ++reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
      +{
      +	return mt->min;
      +}
      +
     -+static int merged_table_seek_record(struct merged_table *mt,
     -+				    struct iterator *it, struct record rec)
     ++static int merged_table_seek_record(struct reftable_merged_table *mt,
     ++				    struct reftable_iterator *it,
     ++				    struct record rec)
      +{
     -+	struct iterator *iters = calloc(sizeof(struct iterator), mt->stack_len);
     ++	struct reftable_iterator *iters = reftable_calloc(
     ++		sizeof(struct reftable_iterator) * mt->stack_len);
      +	struct merged_iter merged = {
      +		.stack = iters,
      +		.typ = record_type(rec),
     @@ -1602,9 +1675,9 @@
      +	if (err < 0) {
      +		int i = 0;
      +		for (i = 0; i < n; i++) {
     -+			iterator_destroy(&iters[i]);
     ++			reftable_iterator_destroy(&iters[i]);
      +		}
     -+		free(iters);
     ++		reftable_free(iters);
      +		return err;
      +	}
      +
     @@ -1615,17 +1688,19 @@
      +	}
      +
      +	{
     -+		struct merged_iter *p = malloc(sizeof(struct merged_iter));
     ++		struct merged_iter *p =
     ++			reftable_malloc(sizeof(struct merged_iter));
      +		*p = merged;
      +		iterator_from_merged_iter(it, p);
      +	}
      +	return 0;
      +}
      +
     -+int merged_table_seek_ref(struct merged_table *mt, struct iterator *it,
     -+			  const char *name)
     ++int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
     ++				   struct reftable_iterator *it,
     ++				   const char *name)
      +{
     -+	struct ref_record ref = {
     ++	struct reftable_ref_record ref = {
      +		.ref_name = (char *)name,
      +	};
      +	struct record rec = { 0 };
     @@ -1633,10 +1708,11 @@
      +	return merged_table_seek_record(mt, it, rec);
      +}
      +
     -+int merged_table_seek_log_at(struct merged_table *mt, struct iterator *it,
     -+			     const char *name, uint64_t update_index)
     ++int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
     ++				      struct reftable_iterator *it,
     ++				      const char *name, uint64_t update_index)
      +{
     -+	struct log_record log = {
     ++	struct reftable_log_record log = {
      +		.ref_name = (char *)name,
      +		.update_index = update_index,
      +	};
     @@ -1645,11 +1721,12 @@
      +	return merged_table_seek_record(mt, it, rec);
      +}
      +
     -+int merged_table_seek_log(struct merged_table *mt, struct iterator *it,
     -+			  const char *name)
     ++int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
     ++				   struct reftable_iterator *it,
     ++				   const char *name)
      +{
      +	uint64_t max = ~((uint64_t)0);
     -+	return merged_table_seek_log_at(mt, it, name, max);
     ++	return reftable_merged_table_seek_log_at(mt, it, name, max);
      +}
      
       diff --git a/reftable/merged.h b/reftable/merged.h
     @@ -1671,8 +1748,8 @@
      +#include "pq.h"
      +#include "reftable.h"
      +
     -+struct merged_table {
     -+	struct reader **stack;
     ++struct reftable_merged_table {
     ++	struct reftable_reader **stack;
      +	int stack_len;
      +	uint32_t hash_id;
      +
     @@ -1681,14 +1758,14 @@
      +};
      +
      +struct merged_iter {
     -+	struct iterator *stack;
     ++	struct reftable_iterator *stack;
      +	uint32_t hash_id;
      +	int stack_len;
      +	byte typ;
      +	struct merged_iter_pqueue pq;
     -+} merged_iter;
     ++};
      +
     -+void merged_table_clear(struct merged_table *mt);
     ++void merged_table_clear(struct reftable_merged_table *mt);
      +
      +#endif
      
     @@ -1719,8 +1796,8 @@
      +
      +	cmp = slice_compare(ak, bk);
      +
     -+	free(slice_yield(&ak));
     -+	free(slice_yield(&bk));
     ++	reftable_free(slice_yield(&ak));
     ++	reftable_free(slice_yield(&bk));
      +
      +	if (cmp == 0) {
      +		return a.index > b.index;
     @@ -1784,7 +1861,8 @@
      +	int i = 0;
      +	if (pq->len == pq->cap) {
      +		pq->cap = 2 * pq->cap + 1;
     -+		pq->heap = realloc(pq->heap, pq->cap * sizeof(struct pq_entry));
     ++		pq->heap = reftable_realloc(pq->heap,
     ++					    pq->cap * sizeof(struct pq_entry));
      +	}
      +
      +	pq->heap[pq->len++] = e;
     @@ -1806,7 +1884,7 @@
      +	int i = 0;
      +	for (i = 0; i < pq->len; i++) {
      +		record_clear(pq->heap[i].rec);
     -+		free(record_yield(&pq->heap[i].rec));
     ++		reftable_free(record_yield(&pq->heap[i].rec));
      +	}
      +	FREE_AND_NULL(pq->heap);
      +	pq->len = pq->cap = 0;
     @@ -1876,20 +1954,22 @@
      +#include "reftable.h"
      +#include "tree.h"
      +
     -+uint64_t block_source_size(struct block_source source)
     ++uint64_t block_source_size(struct reftable_block_source source)
      +{
      +	return source.ops->size(source.arg);
      +}
      +
     -+int block_source_read_block(struct block_source source, struct block *dest,
     -+			    uint64_t off, uint32_t size)
     ++int block_source_read_block(struct reftable_block_source source,
     ++			    struct reftable_block *dest, uint64_t off,
     ++			    uint32_t size)
      +{
      +	int result = source.ops->read_block(source.arg, dest, off, size);
      +	dest->source = source;
      +	return result;
      +}
      +
     -+void block_source_return_block(struct block_source source, struct block *blockp)
     ++void block_source_return_block(struct reftable_block_source source,
     ++			       struct reftable_block *blockp)
      +{
      +	source.ops->return_block(source.arg, blockp);
      +	blockp->data = NULL;
     @@ -1898,7 +1978,7 @@
      +	blockp->source.arg = NULL;
      +}
      +
     -+void block_source_close(struct block_source *source)
     ++void block_source_close(struct reftable_block_source *source)
      +{
      +	if (source->ops == NULL) {
      +		return;
     @@ -1908,7 +1988,8 @@
      +	source->ops = NULL;
      +}
      +
     -+static struct reader_offsets *reader_offsets_for(struct reader *r, byte typ)
     ++static struct reftable_reader_offsets *
     ++reader_offsets_for(struct reftable_reader *r, byte typ)
      +{
      +	switch (typ) {
      +	case BLOCK_TYPE_REF:
     @@ -1921,7 +2002,8 @@
      +	abort();
      +}
      +
     -+static int reader_get_block(struct reader *r, struct block *dest, uint64_t off,
     ++static int reader_get_block(struct reftable_reader *r,
     ++			    struct reftable_block *dest, uint64_t off,
      +			    uint32_t sz)
      +{
      +	if (off >= r->size) {
     @@ -1935,22 +2017,22 @@
      +	return block_source_read_block(r->source, dest, off, sz);
      +}
      +
     -+void reader_return_block(struct reader *r, struct block *p)
     ++void reader_return_block(struct reftable_reader *r, struct reftable_block *p)
      +{
      +	block_source_return_block(r->source, p);
      +}
      +
     -+uint32_t reader_hash_id(struct reader *r)
     ++uint32_t reftable_reader_hash_id(struct reftable_reader *r)
      +{
      +	return r->hash_id;
      +}
      +
     -+const char *reader_name(struct reader *r)
     ++const char *reader_name(struct reftable_reader *r)
      +{
      +	return r->name;
      +}
      +
     -+static int parse_footer(struct reader *r, byte *footer, byte *header)
     ++static int parse_footer(struct reftable_reader *r, byte *footer, byte *header)
      +{
      +	byte *f = footer;
      +	int err = 0;
     @@ -1960,25 +2042,12 @@
      +	}
      +	f += 4;
      +
     -+	if (memcmp(footer, header, HEADER_SIZE)) {
     ++	if (memcmp(footer, header, header_size(r->version))) {
      +		err = FORMAT_ERROR;
      +		goto exit;
      +	}
      +
     -+	r->hash_id = SHA1_ID;
     -+	{
     -+		byte version = *f++;
     -+		if (version == 2) {
     -+			/* DO NOT SUBMIT.  Not yet in the standard. */
     -+			r->hash_id = SHA256_ID;
     -+			version = 1;
     -+		}
     -+		if (version != 1) {
     -+			err = FORMAT_ERROR;
     -+			goto exit;
     -+		}
     -+	}
     -+
     ++	f++;
      +	r->block_size = get_be24(f);
      +
      +	f += 3;
     @@ -1987,6 +2056,22 @@
      +	r->max_update_index = get_be64(f);
      +	f += 8;
      +
     ++	if (r->version == 1) {
     ++		r->hash_id = SHA1_ID;
     ++	} else {
     ++		r->hash_id = get_be32(f);
     ++		switch (r->hash_id) {
     ++		case SHA1_ID:
     ++			break;
     ++		case SHA256_ID:
     ++			break;
     ++		default:
     ++			err = FORMAT_ERROR;
     ++			goto exit;
     ++		}
     ++		f += 4;
     ++	}
     ++
      +	r->ref_offsets.index_offset = get_be64(f);
      +	f += 8;
      +
     @@ -2014,7 +2099,7 @@
      +	}
      +
      +	{
     -+		byte first_block_typ = header[HEADER_SIZE];
     ++		byte first_block_typ = header[header_size(r->version)];
      +		r->ref_offsets.present = (first_block_typ == BLOCK_TYPE_REF);
      +		r->ref_offsets.offset = 0;
      +		r->log_offsets.present = (first_block_typ == BLOCK_TYPE_LOG ||
     @@ -2026,27 +2111,40 @@
      +	return err;
      +}
      +
     -+int init_reader(struct reader *r, struct block_source source, const char *name)
     ++int init_reader(struct reftable_reader *r, struct reftable_block_source source,
     ++		const char *name)
      +{
     -+	struct block footer = { 0 };
     -+	struct block header = { 0 };
     ++	struct reftable_block footer = { 0 };
     ++	struct reftable_block header = { 0 };
      +	int err = 0;
      +
     -+	memset(r, 0, sizeof(struct reader));
     -+	r->size = block_source_size(source) - FOOTER_SIZE;
     -+	r->source = source;
     -+	r->name = xstrdup(name);
     -+	r->hash_id = 0;
     ++	memset(r, 0, sizeof(struct reftable_reader));
      +
     -+	err = block_source_read_block(source, &footer, r->size, FOOTER_SIZE);
     -+	if (err != FOOTER_SIZE) {
     ++	/* Need +1 to read type of first block. */
     ++	err = block_source_read_block(source, &header, 0, header_size(2) + 1);
     ++	if (err != header_size(2) + 1) {
      +		err = IO_ERROR;
      +		goto exit;
      +	}
      +
     -+	/* Need +1 to read type of first block. */
     -+	err = reader_get_block(r, &header, 0, HEADER_SIZE + 1);
     -+	if (err != HEADER_SIZE + 1) {
     ++	if (memcmp(header.data, "REFT", 4)) {
     ++		err = FORMAT_ERROR;
     ++		goto exit;
     ++	}
     ++	r->version = header.data[4];
     ++	if (r->version != 1 && r->version != 2) {
     ++		err = FORMAT_ERROR;
     ++		goto exit;
     ++	}
     ++
     ++	r->size = block_source_size(source) - footer_size(r->version);
     ++	r->source = source;
     ++	r->name = xstrdup(name);
     ++	r->hash_id = 0;
     ++
     ++	err = block_source_read_block(source, &footer, r->size,
     ++				      footer_size(r->version));
     ++	if (err != footer_size(r->version)) {
      +		err = IO_ERROR;
      +		goto exit;
      +	}
     @@ -2059,10 +2157,10 @@
      +}
      +
      +struct table_iter {
     -+	struct reader *r;
     ++	struct reftable_reader *r;
      +	byte typ;
      +	uint64_t block_off;
     -+	struct block_iter bi;
     ++	struct reftable_block_iter bi;
      +	bool finished;
      +};
      +
     @@ -2080,7 +2178,7 @@
      +{
      +	int res = block_iter_next(&ti->bi, rec);
      +	if (res == 0 && record_type(rec) == BLOCK_TYPE_REF) {
     -+		((struct ref_record *)rec.data)->update_index +=
     ++		((struct reftable_ref_record *)rec.data)->update_index +=
      +			ti->r->min_update_index;
      +	}
      +
     @@ -2099,12 +2197,13 @@
      +	ti->bi.next_off = 0;
      +}
      +
     -+static int32_t extract_block_size(byte *data, byte *typ, uint64_t off)
     ++static int32_t extract_block_size(byte *data, byte *typ, uint64_t off,
     ++				  int version)
      +{
      +	int32_t result = 0;
      +
      +	if (off == 0) {
     -+		data += 24;
     ++		data += header_size(version);
      +	}
      +
      +	*typ = data[0];
     @@ -2114,15 +2213,16 @@
      +	return result;
      +}
      +
     -+int reader_init_block_reader(struct reader *r, struct block_reader *br,
     ++int reader_init_block_reader(struct reftable_reader *r,
     ++			     struct reftable_block_reader *br,
      +			     uint64_t next_off, byte want_typ)
      +{
      +	int32_t guess_block_size = r->block_size ? r->block_size :
      +						   DEFAULT_BLOCK_SIZE;
     -+	struct block block = { 0 };
     ++	struct reftable_block block = { 0 };
      +	byte block_typ = 0;
      +	int err = 0;
     -+	uint32_t header_off = next_off ? 0 : HEADER_SIZE;
     ++	uint32_t header_off = next_off ? 0 : header_size(r->version);
      +	int32_t block_size = 0;
      +
      +	if (next_off >= r->size) {
     @@ -2134,7 +2234,8 @@
      +		return err;
      +	}
      +
     -+	block_size = extract_block_size(block.data, &block_typ, next_off);
     ++	block_size = extract_block_size(block.data, &block_typ, next_off,
     ++					r->version);
      +	if (block_size < 0) {
      +		return block_size;
      +	}
     @@ -2160,7 +2261,7 @@
      +				 struct table_iter *src)
      +{
      +	uint64_t next_block_off = src->block_off + src->bi.br->full_block_size;
     -+	struct block_reader br = { 0 };
     ++	struct reftable_block_reader br = { 0 };
      +	int err = 0;
      +
      +	dest->r = src->r;
     @@ -2177,7 +2278,8 @@
      +	}
      +
      +	{
     -+		struct block_reader *brp = malloc(sizeof(struct block_reader));
     ++		struct reftable_block_reader *brp =
     ++			reftable_malloc(sizeof(struct reftable_block_reader));
      +		*brp = br;
      +
      +		dest->finished = false;
     @@ -2229,29 +2331,30 @@
      +	block_iter_close(&ti->bi);
      +}
      +
     -+struct iterator_vtable table_iter_vtable = {
     ++struct reftable_iterator_vtable table_iter_vtable = {
      +	.next = &table_iter_next_void,
      +	.close = &table_iter_close,
      +};
      +
     -+static void iterator_from_table_iter(struct iterator *it, struct table_iter *ti)
     ++static void iterator_from_table_iter(struct reftable_iterator *it,
     ++				     struct table_iter *ti)
      +{
      +	it->iter_arg = ti;
      +	it->ops = &table_iter_vtable;
      +}
      +
     -+static int reader_table_iter_at(struct reader *r, struct table_iter *ti,
     -+				uint64_t off, byte typ)
     ++static int reader_table_iter_at(struct reftable_reader *r,
     ++				struct table_iter *ti, uint64_t off, byte typ)
      +{
     -+	struct block_reader br = { 0 };
     -+	struct block_reader *brp = NULL;
     ++	struct reftable_block_reader br = { 0 };
     ++	struct reftable_block_reader *brp = NULL;
      +
      +	int err = reader_init_block_reader(r, &br, off, typ);
      +	if (err != 0) {
      +		return err;
      +	}
      +
     -+	brp = malloc(sizeof(struct block_reader));
     ++	brp = reftable_malloc(sizeof(struct reftable_block_reader));
      +	*brp = br;
      +	ti->r = r;
      +	ti->typ = block_reader_type(brp);
     @@ -2260,10 +2363,10 @@
      +	return 0;
      +}
      +
     -+static int reader_start(struct reader *r, struct table_iter *ti, byte typ,
     -+			bool index)
     ++static int reader_start(struct reftable_reader *r, struct table_iter *ti,
     ++			byte typ, bool index)
      +{
     -+	struct reader_offsets *offs = reader_offsets_for(r, typ);
     ++	struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
      +	uint64_t off = offs->offset;
      +	if (index) {
      +		off = offs->index_offset;
     @@ -2276,7 +2379,7 @@
      +	return reader_table_iter_at(r, ti, off, typ);
      +}
      +
     -+static int reader_seek_linear(struct reader *r, struct table_iter *ti,
     ++static int reader_seek_linear(struct reftable_reader *r, struct table_iter *ti,
      +			      struct record want)
      +{
      +	struct record rec = new_record(record_type(want));
     @@ -2321,14 +2424,14 @@
      +exit:
      +	block_iter_close(&next.bi);
      +	record_clear(rec);
     -+	free(record_yield(&rec));
     -+	free(slice_yield(&want_key));
     -+	free(slice_yield(&got_key));
     ++	reftable_free(record_yield(&rec));
     ++	reftable_free(slice_yield(&want_key));
     ++	reftable_free(slice_yield(&got_key));
      +	return err;
      +}
      +
     -+static int reader_seek_indexed(struct reader *r, struct iterator *it,
     -+			       struct record rec)
     ++static int reader_seek_indexed(struct reftable_reader *r,
     ++			       struct reftable_iterator *it, struct record rec)
      +{
      +	struct index_record want_index = { 0 };
      +	struct record want_index_rec = { 0 };
     @@ -2380,7 +2483,7 @@
      +
      +	if (err == 0) {
      +		struct table_iter *malloced =
     -+			calloc(sizeof(struct table_iter), 1);
     ++			reftable_calloc(sizeof(struct table_iter));
      +		table_iter_copy_from(malloced, &next);
      +		iterator_from_table_iter(it, malloced);
      +	}
     @@ -2392,10 +2495,11 @@
      +	return err;
      +}
      +
     -+static int reader_seek_internal(struct reader *r, struct iterator *it,
     -+				struct record rec)
     ++static int reader_seek_internal(struct reftable_reader *r,
     ++				struct reftable_iterator *it, struct record rec)
      +{
     -+	struct reader_offsets *offs = reader_offsets_for(r, record_type(rec));
     ++	struct reftable_reader_offsets *offs =
     ++		reader_offsets_for(r, record_type(rec));
      +	uint64_t idx = offs->index_offset;
      +	struct table_iter ti = { 0 };
      +	int err = 0;
     @@ -2413,7 +2517,8 @@
      +	}
      +
      +	{
     -+		struct table_iter *p = malloc(sizeof(struct table_iter));
     ++		struct table_iter *p =
     ++			reftable_malloc(sizeof(struct table_iter));
      +		*p = ti;
      +		iterator_from_table_iter(it, p);
      +	}
     @@ -2421,11 +2526,12 @@
      +	return 0;
      +}
      +
     -+int reader_seek(struct reader *r, struct iterator *it, struct record rec)
     ++int reader_seek(struct reftable_reader *r, struct reftable_iterator *it,
     ++		struct record rec)
      +{
      +	byte typ = record_type(rec);
      +
     -+	struct reader_offsets *offs = reader_offsets_for(r, typ);
     ++	struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
      +	if (!offs->present) {
      +		iterator_set_empty(it);
      +		return 0;
     @@ -2434,9 +2540,10 @@
      +	return reader_seek_internal(r, it, rec);
      +}
      +
     -+int reader_seek_ref(struct reader *r, struct iterator *it, const char *name)
     ++int reftable_reader_seek_ref(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, const char *name)
      +{
     -+	struct ref_record ref = {
     ++	struct reftable_ref_record ref = {
      +		.ref_name = (char *)name,
      +	};
      +	struct record rec = { 0 };
     @@ -2444,10 +2551,11 @@
      +	return reader_seek(r, it, rec);
      +}
      +
     -+int reader_seek_log_at(struct reader *r, struct iterator *it, const char *name,
     -+		       uint64_t update_index)
     ++int reftable_reader_seek_log_at(struct reftable_reader *r,
     ++				struct reftable_iterator *it, const char *name,
     ++				uint64_t update_index)
      +{
     -+	struct log_record log = {
     ++	struct reftable_log_record log = {
      +		.ref_name = (char *)name,
      +		.update_index = update_index,
      +	};
     @@ -2456,45 +2564,49 @@
      +	return reader_seek(r, it, rec);
      +}
      +
     -+int reader_seek_log(struct reader *r, struct iterator *it, const char *name)
     ++int reftable_reader_seek_log(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, const char *name)
      +{
      +	uint64_t max = ~((uint64_t)0);
     -+	return reader_seek_log_at(r, it, name, max);
     ++	return reftable_reader_seek_log_at(r, it, name, max);
      +}
      +
     -+void reader_close(struct reader *r)
     ++void reader_close(struct reftable_reader *r)
      +{
      +	block_source_close(&r->source);
      +	FREE_AND_NULL(r->name);
      +}
      +
     -+int new_reader(struct reader **p, struct block_source src, char const *name)
     ++int reftable_new_reader(struct reftable_reader **p,
     ++			struct reftable_block_source src, char const *name)
      +{
     -+	struct reader *rd = calloc(sizeof(struct reader), 1);
     ++	struct reftable_reader *rd =
     ++		reftable_calloc(sizeof(struct reftable_reader));
      +	int err = init_reader(rd, src, name);
      +	if (err == 0) {
      +		*p = rd;
      +	} else {
     -+		free(rd);
     ++		reftable_free(rd);
      +	}
      +	return err;
      +}
      +
     -+void reader_free(struct reader *r)
     ++void reftable_reader_free(struct reftable_reader *r)
      +{
      +	reader_close(r);
     -+	free(r);
     ++	reftable_free(r);
      +}
      +
     -+static int reader_refs_for_indexed(struct reader *r, struct iterator *it,
     -+				   byte *oid)
     ++static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
     ++					    struct reftable_iterator *it,
     ++					    byte *oid)
      +{
      +	struct obj_record want = {
      +		.hash_prefix = oid,
      +		.hash_prefix_len = r->object_id_len,
      +	};
      +	struct record want_rec = { 0 };
     -+	struct iterator oit = { 0 };
     ++	struct reftable_iterator oit = { 0 };
      +	struct obj_record got = { 0 };
      +	struct record got_rec = { 0 };
      +	int err = 0;
     @@ -2508,7 +2620,7 @@
      +
      +	record_from_obj(&got_rec, &got);
      +	err = iterator_next(oit, got_rec);
     -+	iterator_destroy(&oit);
     ++	reftable_iterator_destroy(&oit);
      +	if (err < 0) {
      +		return err;
      +	}
     @@ -2537,18 +2649,19 @@
      +	return 0;
      +}
      +
     -+static int reader_refs_for_unindexed(struct reader *r, struct iterator *it,
     -+				     byte *oid, int oid_len)
     ++static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
     ++					      struct reftable_iterator *it,
     ++					      byte *oid, int oid_len)
      +{
     -+	struct table_iter *ti = calloc(sizeof(struct table_iter), 1);
     ++	struct table_iter *ti = reftable_calloc(sizeof(struct table_iter));
      +	struct filtering_ref_iterator *filter = NULL;
      +	int err = reader_start(r, ti, BLOCK_TYPE_REF, false);
      +	if (err < 0) {
     -+		free(ti);
     ++		reftable_free(ti);
      +		return err;
      +	}
      +
     -+	filter = calloc(sizeof(struct filtering_ref_iterator), 1);
     ++	filter = reftable_calloc(sizeof(struct filtering_ref_iterator));
      +	slice_resize(&filter->oid, oid_len);
      +	memcpy(filter->oid.buf, oid, oid_len);
      +	filter->r = r;
     @@ -2559,21 +2672,22 @@
      +	return 0;
      +}
      +
     -+int reader_refs_for(struct reader *r, struct iterator *it, byte *oid,
     -+		    int oid_len)
     ++int reftable_reader_refs_for(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, byte *oid,
     ++			     int oid_len)
      +{
      +	if (r->obj_offsets.present) {
     -+		return reader_refs_for_indexed(r, it, oid);
     ++		return reftable_reader_refs_for_indexed(r, it, oid);
      +	}
     -+	return reader_refs_for_unindexed(r, it, oid, oid_len);
     ++	return reftable_reader_refs_for_unindexed(r, it, oid, oid_len);
      +}
      +
     -+uint64_t reader_max_update_index(struct reader *r)
     ++uint64_t reftable_reader_max_update_index(struct reftable_reader *r)
      +{
      +	return r->max_update_index;
      +}
      +
     -+uint64_t reader_min_update_index(struct reader *r)
     ++uint64_t reftable_reader_min_update_index(struct reftable_reader *r)
      +{
      +	return r->min_update_index;
      +}
     @@ -2598,40 +2712,48 @@
      +#include "record.h"
      +#include "reftable.h"
      +
     -+uint64_t block_source_size(struct block_source source);
     ++uint64_t block_source_size(struct reftable_block_source source);
      +
     -+int block_source_read_block(struct block_source source, struct block *dest,
     -+			    uint64_t off, uint32_t size);
     -+void block_source_return_block(struct block_source source, struct block *ret);
     -+void block_source_close(struct block_source *source);
     ++int block_source_read_block(struct reftable_block_source source,
     ++			    struct reftable_block *dest, uint64_t off,
     ++			    uint32_t size);
     ++void block_source_return_block(struct reftable_block_source source,
     ++			       struct reftable_block *ret);
     ++void block_source_close(struct reftable_block_source *source);
      +
     -+struct reader_offsets {
     ++struct reftable_reader_offsets {
      +	bool present;
      +	uint64_t offset;
      +	uint64_t index_offset;
      +};
      +
     -+struct reader {
     ++struct reftable_reader {
      +	char *name;
     -+	struct block_source source;
     ++	struct reftable_block_source source;
      +	uint32_t hash_id;
     ++
     ++	// Size of the file, excluding the footer.
      +	uint64_t size;
      +	uint32_t block_size;
      +	uint64_t min_update_index;
      +	uint64_t max_update_index;
      +	int object_id_len;
     ++	int version;
      +
     -+	struct reader_offsets ref_offsets;
     -+	struct reader_offsets obj_offsets;
     -+	struct reader_offsets log_offsets;
     ++	struct reftable_reader_offsets ref_offsets;
     ++	struct reftable_reader_offsets obj_offsets;
     ++	struct reftable_reader_offsets log_offsets;
      +};
      +
     -+int init_reader(struct reader *r, struct block_source source, const char *name);
     -+int reader_seek(struct reader *r, struct iterator *it, struct record rec);
     -+void reader_close(struct reader *r);
     -+const char *reader_name(struct reader *r);
     -+void reader_return_block(struct reader *r, struct block *p);
     -+int reader_init_block_reader(struct reader *r, struct block_reader *br,
     ++int init_reader(struct reftable_reader *r, struct reftable_block_source source,
     ++		const char *name);
     ++int reader_seek(struct reftable_reader *r, struct reftable_iterator *it,
     ++		struct record rec);
     ++void reader_close(struct reftable_reader *r);
     ++const char *reader_name(struct reftable_reader *r);
     ++void reader_return_block(struct reftable_reader *r, struct reftable_block *p);
     ++int reader_init_block_reader(struct reftable_reader *r,
     ++			     struct reftable_block_reader *br,
      +			     uint64_t next_off, byte want_typ);
      +
      +#endif
     @@ -2649,6 +2771,8 @@
      +https://developers.google.com/open-source/licenses/bsd
      +*/
      +
     ++/* record.c - methods for different types of records. */
     ++
      +#include "record.h"
      +
      +#include "system.h"
     @@ -2656,18 +2780,6 @@
      +#include "constants.h"
      +#include "reftable.h"
      +
     -+int is_block_type(byte typ)
     -+{
     -+	switch (typ) {
     -+	case BLOCK_TYPE_REF:
     -+	case BLOCK_TYPE_LOG:
     -+	case BLOCK_TYPE_OBJ:
     -+	case BLOCK_TYPE_INDEX:
     -+		return true;
     -+	}
     -+	return false;
     -+}
     -+
      +int get_var_int(uint64_t *dest, struct slice in)
      +{
      +	int ptr = 0;
     @@ -2716,17 +2828,16 @@
      +	}
      +}
      +
     -+int common_prefix_size(struct slice a, struct slice b)
     ++int is_block_type(byte typ)
      +{
     -+	int p = 0;
     -+	while (p < a.len && p < b.len) {
     -+		if (a.buf[p] != b.buf[p]) {
     -+			break;
     -+		}
     -+		p++;
     ++	switch (typ) {
     ++	case BLOCK_TYPE_REF:
     ++	case BLOCK_TYPE_LOG:
     ++	case BLOCK_TYPE_OBJ:
     ++	case BLOCK_TYPE_INDEX:
     ++		return true;
      +	}
     -+
     -+	return p;
     ++	return false;
      +}
      +
      +static int decode_string(struct slice *dest, struct slice in)
     @@ -2737,8 +2848,7 @@
      +	if (n <= 0) {
      +		return -1;
      +	}
     -+	in.buf += n;
     -+	in.len -= n;
     ++	slice_consume(&in, n);
      +	if (in.len < tsize) {
      +		return -1;
      +	}
     @@ -2746,12 +2856,29 @@
      +	slice_resize(dest, tsize + 1);
      +	dest->buf[tsize] = 0;
      +	memcpy(dest->buf, in.buf, tsize);
     -+	in.buf += tsize;
     -+	in.len -= tsize;
     ++	slice_consume(&in, tsize);
      +
      +	return start_len - in.len;
      +}
      +
     ++static int encode_string(char *str, struct slice s)
     ++{
     ++	struct slice start = s;
     ++	int l = strlen(str);
     ++	int n = put_var_int(s, l);
     ++	if (n < 0) {
     ++		return -1;
     ++	}
     ++	slice_consume(&s, n);
     ++	if (s.len < l) {
     ++		return -1;
     ++	}
     ++	memcpy(s.buf, str, l);
     ++	slice_consume(&s, l);
     ++
     ++	return start.len - s.len;
     ++}
     ++
      +int encode_key(bool *restart, struct slice dest, struct slice prev_key,
      +	       struct slice key, byte extra)
      +{
     @@ -2762,8 +2889,7 @@
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	dest.buf += n;
     -+	dest.len -= n;
     ++	slice_consume(&dest, n);
      +
      +	*restart = (prefix_len == 0);
      +
     @@ -2771,39 +2897,77 @@
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	dest.buf += n;
     -+	dest.len -= n;
     ++	slice_consume(&dest, n);
      +
      +	if (dest.len < suffix_len) {
      +		return -1;
      +	}
      +	memcpy(dest.buf, key.buf + prefix_len, suffix_len);
     -+	dest.buf += suffix_len;
     -+	dest.len -= suffix_len;
     ++	slice_consume(&dest, suffix_len);
      +
      +	return start.len - dest.len;
      +}
      +
     -+static byte ref_record_type(void)
     ++int decode_key(struct slice *key, byte *extra, struct slice last_key,
     ++	       struct slice in)
     ++{
     ++	int start_len = in.len;
     ++	uint64_t prefix_len = 0;
     ++	uint64_t suffix_len = 0;
     ++	int n = get_var_int(&prefix_len, in);
     ++	if (n < 0) {
     ++		return -1;
     ++	}
     ++	slice_consume(&in, n);
     ++
     ++	if (prefix_len > last_key.len) {
     ++		return -1;
     ++	}
     ++
     ++	n = get_var_int(&suffix_len, in);
     ++	if (n <= 0) {
     ++		return -1;
     ++	}
     ++	slice_consume(&in, n);
     ++
     ++	*extra = (byte)(suffix_len & 0x7);
     ++	suffix_len >>= 3;
     ++
     ++	if (in.len < suffix_len) {
     ++		return -1;
     ++	}
     ++
     ++	slice_resize(key, suffix_len + prefix_len);
     ++	memcpy(key->buf, last_key.buf, prefix_len);
     ++
     ++	memcpy(key->buf + prefix_len, in.buf, suffix_len);
     ++	slice_consume(&in, suffix_len);
     ++
     ++	return start_len - in.len;
     ++}
     ++
     ++static byte reftable_ref_record_type(void)
      +{
      +	return BLOCK_TYPE_REF;
      +}
      +
     -+static void ref_record_key(const void *r, struct slice *dest)
     ++static void reftable_ref_record_key(const void *r, struct slice *dest)
      +{
     -+	const struct ref_record *rec = (const struct ref_record *)r;
     ++	const struct reftable_ref_record *rec =
     ++		(const struct reftable_ref_record *)r;
      +	slice_set_string(dest, rec->ref_name);
      +}
      +
     -+static void ref_record_copy_from(void *rec, const void *src_rec, int hash_size)
     ++static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
     ++					  int hash_size)
      +{
     -+	struct ref_record *ref = (struct ref_record *)rec;
     -+	struct ref_record *src = (struct ref_record *)src_rec;
     ++	struct reftable_ref_record *ref = (struct reftable_ref_record *)rec;
     ++	struct reftable_ref_record *src = (struct reftable_ref_record *)src_rec;
      +	assert(hash_size > 0);
      +
      +	/* This is simple and correct, but we could probably reuse the hash
      +	   fields. */
     -+	ref_record_clear(ref);
     ++	reftable_ref_record_clear(ref);
      +	if (src->ref_name != NULL) {
      +		ref->ref_name = xstrdup(src->ref_name);
      +	}
     @@ -2813,12 +2977,12 @@
      +	}
      +
      +	if (src->target_value != NULL) {
     -+		ref->target_value = malloc(hash_size);
     ++		ref->target_value = reftable_malloc(hash_size);
      +		memcpy(ref->target_value, src->target_value, hash_size);
      +	}
      +
      +	if (src->value != NULL) {
     -+		ref->value = malloc(hash_size);
     ++		ref->value = reftable_malloc(hash_size);
      +		memcpy(ref->value, src->value, hash_size);
      +	}
      +	ref->update_index = src->update_index;
     @@ -2845,7 +3009,7 @@
      +	}
      +}
      +
     -+void ref_record_print(struct ref_record *ref, int hash_size)
     ++void reftable_ref_record_print(struct reftable_ref_record *ref, int hash_size)
      +{
      +	char hex[SHA256_SIZE + 1] = { 0 };
      +
     @@ -2864,23 +3028,24 @@
      +	printf("}\n");
      +}
      +
     -+static void ref_record_clear_void(void *rec)
     ++static void reftable_ref_record_clear_void(void *rec)
      +{
     -+	ref_record_clear((struct ref_record *)rec);
     ++	reftable_ref_record_clear((struct reftable_ref_record *)rec);
      +}
      +
     -+void ref_record_clear(struct ref_record *ref)
     ++void reftable_ref_record_clear(struct reftable_ref_record *ref)
      +{
     -+	free(ref->ref_name);
     -+	free(ref->target);
     -+	free(ref->target_value);
     -+	free(ref->value);
     -+	memset(ref, 0, sizeof(struct ref_record));
     ++	reftable_free(ref->ref_name);
     ++	reftable_free(ref->target);
     ++	reftable_free(ref->target_value);
     ++	reftable_free(ref->value);
     ++	memset(ref, 0, sizeof(struct reftable_ref_record));
      +}
      +
     -+static byte ref_record_val_type(const void *rec)
     ++static byte reftable_ref_record_val_type(const void *rec)
      +{
     -+	const struct ref_record *r = (const struct ref_record *)rec;
     ++	const struct reftable_ref_record *r =
     ++		(const struct reftable_ref_record *)rec;
      +	if (r->value != NULL) {
      +		if (r->target_value != NULL) {
      +			return 2;
     @@ -2893,45 +3058,25 @@
      +	return 0;
      +}
      +
     -+static int encode_string(char *str, struct slice s)
     -+{
     -+	struct slice start = s;
     -+	int l = strlen(str);
     -+	int n = put_var_int(s, l);
     -+	if (n < 0) {
     -+		return -1;
     -+	}
     -+	s.buf += n;
     -+	s.len -= n;
     -+	if (s.len < l) {
     -+		return -1;
     -+	}
     -+	memcpy(s.buf, str, l);
     -+	s.buf += l;
     -+	s.len -= l;
     -+
     -+	return start.len - s.len;
     -+}
     -+
     -+static int ref_record_encode(const void *rec, struct slice s, int hash_size)
     ++static int reftable_ref_record_encode(const void *rec, struct slice s,
     ++				      int hash_size)
      +{
     -+	const struct ref_record *r = (const struct ref_record *)rec;
     ++	const struct reftable_ref_record *r =
     ++		(const struct reftable_ref_record *)rec;
      +	struct slice start = s;
      +	int n = put_var_int(s, r->update_index);
      +	assert(hash_size > 0);
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.buf += n;
     -+	s.len -= n;
     ++	slice_consume(&s, n);
      +
      +	if (r->value != NULL) {
      +		if (s.len < hash_size) {
      +			return -1;
      +		}
      +		memcpy(s.buf, r->value, hash_size);
     -+		s.buf += hash_size;
     -+		s.len -= hash_size;
     ++		slice_consume(&s, hash_size);
      +	}
      +
      +	if (r->target_value != NULL) {
     @@ -2939,8 +3084,7 @@
      +			return -1;
      +		}
      +		memcpy(s.buf, r->target_value, hash_size);
     -+		s.buf += hash_size;
     -+		s.len -= hash_size;
     ++		slice_consume(&s, hash_size);
      +	}
      +
      +	if (r->target != NULL) {
     @@ -2948,17 +3092,17 @@
      +		if (n < 0) {
      +			return -1;
      +		}
     -+		s.buf += n;
     -+		s.len -= n;
     ++		slice_consume(&s, n);
      +	}
      +
      +	return start.len - s.len;
      +}
      +
     -+static int ref_record_decode(void *rec, struct slice key, byte val_type,
     -+			     struct slice in, int hash_size)
     ++static int reftable_ref_record_decode(void *rec, struct slice key,
     ++				      byte val_type, struct slice in,
     ++				      int hash_size)
      +{
     -+	struct ref_record *r = (struct ref_record *)rec;
     ++	struct reftable_ref_record *r = (struct reftable_ref_record *)rec;
      +	struct slice start = in;
      +	bool seen_value = false;
      +	bool seen_target_value = false;
     @@ -2970,10 +3114,9 @@
      +	}
      +	assert(hash_size > 0);
      +
     -+	in.buf += n;
     -+	in.len -= n;
     ++	slice_consume(&in, n);
      +
     -+	r->ref_name = realloc(r->ref_name, key.len + 1);
     ++	r->ref_name = reftable_realloc(r->ref_name, key.len + 1);
      +	memcpy(r->ref_name, key.buf, key.len);
      +	r->ref_name[key.len] = 0;
      +
     @@ -2985,22 +3128,20 @@
      +		}
      +
      +		if (r->value == NULL) {
     -+			r->value = malloc(hash_size);
     ++			r->value = reftable_malloc(hash_size);
      +		}
      +		seen_value = true;
      +		memcpy(r->value, in.buf, hash_size);
     -+		in.buf += hash_size;
     -+		in.len -= hash_size;
     ++		slice_consume(&in, hash_size);
      +		if (val_type == 1) {
      +			break;
      +		}
      +		if (r->target_value == NULL) {
     -+			r->target_value = malloc(hash_size);
     ++			r->target_value = reftable_malloc(hash_size);
      +		}
      +		seen_target_value = true;
      +		memcpy(r->target_value, in.buf, hash_size);
     -+		in.buf += hash_size;
     -+		in.len -= hash_size;
     ++		slice_consume(&in, hash_size);
      +		break;
      +	case 3: {
      +		struct slice dest = { 0 };
     @@ -3008,8 +3149,7 @@
      +		if (n < 0) {
      +			return -1;
      +		}
     -+		in.buf += n;
     -+		in.len -= n;
     ++		slice_consume(&in, n);
      +		seen_target = true;
      +		r->target = (char *)slice_as_string(&dest);
      +	} break;
     @@ -3034,55 +3174,14 @@
      +	return start.len - in.len;
      +}
      +
     -+int decode_key(struct slice *key, byte *extra, struct slice last_key,
     -+	       struct slice in)
     -+{
     -+	int start_len = in.len;
     -+	uint64_t prefix_len = 0;
     -+	uint64_t suffix_len = 0;
     -+	int n = get_var_int(&prefix_len, in);
     -+	if (n < 0) {
     -+		return -1;
     -+	}
     -+	in.buf += n;
     -+	in.len -= n;
     -+
     -+	if (prefix_len > last_key.len) {
     -+		return -1;
     -+	}
     -+
     -+	n = get_var_int(&suffix_len, in);
     -+	if (n <= 0) {
     -+		return -1;
     -+	}
     -+	in.buf += n;
     -+	in.len -= n;
     -+
     -+	*extra = (byte)(suffix_len & 0x7);
     -+	suffix_len >>= 3;
     -+
     -+	if (in.len < suffix_len) {
     -+		return -1;
     -+	}
     -+
     -+	slice_resize(key, suffix_len + prefix_len);
     -+	memcpy(key->buf, last_key.buf, prefix_len);
     -+
     -+	memcpy(key->buf + prefix_len, in.buf, suffix_len);
     -+	in.buf += suffix_len;
     -+	in.len -= suffix_len;
     -+
     -+	return start_len - in.len;
     -+}
     -+
     -+struct record_vtable ref_record_vtable = {
     -+	.key = &ref_record_key,
     -+	.type = &ref_record_type,
     -+	.copy_from = &ref_record_copy_from,
     -+	.val_type = &ref_record_val_type,
     -+	.encode = &ref_record_encode,
     -+	.decode = &ref_record_decode,
     -+	.clear = &ref_record_clear_void,
     ++struct record_vtable reftable_ref_record_vtable = {
     ++	.key = &reftable_ref_record_key,
     ++	.type = &reftable_ref_record_type,
     ++	.copy_from = &reftable_ref_record_copy_from,
     ++	.val_type = &reftable_ref_record_val_type,
     ++	.encode = &reftable_ref_record_encode,
     ++	.decode = &reftable_ref_record_decode,
     ++	.clear = &reftable_ref_record_clear_void,
      +};
      +
      +static byte obj_record_type(void)
     @@ -3103,12 +3202,12 @@
      +	const struct obj_record *src = (const struct obj_record *)src_rec;
      +
      +	*ref = *src;
     -+	ref->hash_prefix = malloc(ref->hash_prefix_len);
     ++	ref->hash_prefix = reftable_malloc(ref->hash_prefix_len);
      +	memcpy(ref->hash_prefix, src->hash_prefix, ref->hash_prefix_len);
      +
      +	{
      +		int olen = ref->offset_len * sizeof(uint64_t);
     -+		ref->offsets = malloc(olen);
     ++		ref->offsets = reftable_malloc(olen);
      +		memcpy(ref->offsets, src->offsets, olen);
      +	}
      +}
     @@ -3140,8 +3239,7 @@
      +		if (n < 0) {
      +			return -1;
      +		}
     -+		s.buf += n;
     -+		s.len -= n;
     ++		slice_consume(&s, n);
      +	}
      +	if (r->offset_len == 0) {
      +		return start.len - s.len;
     @@ -3150,8 +3248,7 @@
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.buf += n;
     -+	s.len -= n;
     ++	slice_consume(&s, n);
      +
      +	{
      +		uint64_t last = r->offsets[0];
     @@ -3161,8 +3258,7 @@
      +			if (n < 0) {
      +				return -1;
      +			}
     -+			s.buf += n;
     -+			s.len -= n;
     ++			slice_consume(&s, n);
      +			last = r->offsets[i];
      +		}
      +	}
     @@ -3176,7 +3272,7 @@
      +	struct obj_record *r = (struct obj_record *)rec;
      +	uint64_t count = val_type;
      +	int n = 0;
     -+	r->hash_prefix = malloc(key.len);
     ++	r->hash_prefix = reftable_malloc(key.len);
      +	memcpy(r->hash_prefix, key.buf, key.len);
      +	r->hash_prefix_len = key.len;
      +
     @@ -3186,8 +3282,7 @@
      +			return n;
      +		}
      +
     -+		in.buf += n;
     -+		in.len -= n;
     ++		slice_consume(&in, n);
      +	}
      +
      +	r->offsets = NULL;
     @@ -3196,16 +3291,14 @@
      +		return start.len - in.len;
      +	}
      +
     -+	r->offsets = malloc(count * sizeof(uint64_t));
     ++	r->offsets = reftable_malloc(count * sizeof(uint64_t));
      +	r->offset_len = count;
      +
      +	n = get_var_int(&r->offsets[0], in);
      +	if (n < 0) {
      +		return n;
      +	}
     -+
     -+	in.buf += n;
     -+	in.len -= n;
     ++	slice_consume(&in, n);
      +
      +	{
      +		uint64_t last = r->offsets[0];
     @@ -3216,9 +3309,7 @@
      +			if (n < 0) {
      +				return n;
      +			}
     -+
     -+			in.buf += n;
     -+			in.len -= n;
     ++			slice_consume(&in, n);
      +
      +			last = r->offsets[j] = (delta + last);
      +			j++;
     @@ -3237,7 +3328,7 @@
      +	.clear = &obj_record_clear,
      +};
      +
     -+void log_record_print(struct log_record *log, int hash_size)
     ++void reftable_log_record_print(struct reftable_log_record *log, int hash_size)
      +{
      +	char hex[SHA256_SIZE + 1] = { 0 };
      +
     @@ -3250,14 +3341,15 @@
      +	printf("%s\n\n%s\n}\n", hex, log->message);
      +}
      +
     -+static byte log_record_type(void)
     ++static byte reftable_log_record_type(void)
      +{
      +	return BLOCK_TYPE_LOG;
      +}
      +
     -+static void log_record_key(const void *r, struct slice *dest)
     ++static void reftable_log_record_key(const void *r, struct slice *dest)
      +{
     -+	const struct log_record *rec = (const struct log_record *)r;
     ++	const struct reftable_log_record *rec =
     ++		(const struct reftable_log_record *)r;
      +	int len = strlen(rec->ref_name);
      +	uint64_t ts = 0;
      +	slice_resize(dest, len + 9);
     @@ -3266,10 +3358,12 @@
      +	put_be64(dest->buf + 1 + len, ts);
      +}
      +
     -+static void log_record_copy_from(void *rec, const void *src_rec, int hash_size)
     ++static void reftable_log_record_copy_from(void *rec, const void *src_rec,
     ++					  int hash_size)
      +{
     -+	struct log_record *dst = (struct log_record *)rec;
     -+	const struct log_record *src = (const struct log_record *)src_rec;
     ++	struct reftable_log_record *dst = (struct reftable_log_record *)rec;
     ++	const struct reftable_log_record *src =
     ++		(const struct reftable_log_record *)src_rec;
      +
      +	*dst = *src;
      +	dst->ref_name = xstrdup(dst->ref_name);
     @@ -3277,46 +3371,54 @@
      +	dst->name = xstrdup(dst->name);
      +	dst->message = xstrdup(dst->message);
      +	if (dst->new_hash != NULL) {
     -+		dst->new_hash = malloc(hash_size);
     ++		dst->new_hash = reftable_malloc(hash_size);
      +		memcpy(dst->new_hash, src->new_hash, hash_size);
      +	}
      +	if (dst->old_hash != NULL) {
     -+		dst->old_hash = malloc(hash_size);
     ++		dst->old_hash = reftable_malloc(hash_size);
      +		memcpy(dst->old_hash, src->old_hash, hash_size);
      +	}
      +}
      +
     -+static void log_record_clear_void(void *rec)
     ++static void reftable_log_record_clear_void(void *rec)
      +{
     -+	struct log_record *r = (struct log_record *)rec;
     -+	log_record_clear(r);
     ++	struct reftable_log_record *r = (struct reftable_log_record *)rec;
     ++	reftable_log_record_clear(r);
      +}
      +
     -+void log_record_clear(struct log_record *r)
     ++void reftable_log_record_clear(struct reftable_log_record *r)
      +{
     -+	free(r->ref_name);
     -+	free(r->new_hash);
     -+	free(r->old_hash);
     -+	free(r->name);
     -+	free(r->email);
     -+	free(r->message);
     -+	memset(r, 0, sizeof(struct log_record));
     ++	reftable_free(r->ref_name);
     ++	reftable_free(r->new_hash);
     ++	reftable_free(r->old_hash);
     ++	reftable_free(r->name);
     ++	reftable_free(r->email);
     ++	reftable_free(r->message);
     ++	memset(r, 0, sizeof(struct reftable_log_record));
      +}
      +
     -+static byte log_record_val_type(const void *rec)
     ++static byte reftable_log_record_val_type(const void *rec)
      +{
     -+	return 1;
     ++	const struct reftable_log_record *log =
     ++		(const struct reftable_log_record *)rec;
     ++
     ++	return reftable_log_record_is_deletion(log) ? 0 : 1;
      +}
      +
      +static byte zero[SHA256_SIZE] = { 0 };
      +
     -+static int log_record_encode(const void *rec, struct slice s, int hash_size)
     ++static int reftable_log_record_encode(const void *rec, struct slice s,
     ++				      int hash_size)
      +{
     -+	struct log_record *r = (struct log_record *)rec;
     ++	struct reftable_log_record *r = (struct reftable_log_record *)rec;
      +	struct slice start = s;
      +	int n = 0;
      +	byte *oldh = r->old_hash;
      +	byte *newh = r->new_hash;
     ++	if (reftable_log_record_is_deletion(r)) {
     ++		return 0;
     ++	}
     ++
      +	if (oldh == NULL) {
      +		oldh = zero;
      +	}
     @@ -3330,53 +3432,48 @@
      +
      +	memcpy(s.buf, oldh, hash_size);
      +	memcpy(s.buf + hash_size, newh, hash_size);
     -+	s.buf += 2 * hash_size;
     -+	s.len -= 2 * hash_size;
     ++	slice_consume(&s, 2 * hash_size);
      +
      +	n = encode_string(r->name ? r->name : "", s);
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.len -= n;
     -+	s.buf += n;
     ++	slice_consume(&s, n);
      +
      +	n = encode_string(r->email ? r->email : "", s);
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.len -= n;
     -+	s.buf += n;
     ++	slice_consume(&s, n);
      +
      +	n = put_var_int(s, r->time);
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.buf += n;
     -+	s.len -= n;
     ++	slice_consume(&s, n);
      +
      +	if (s.len < 2) {
      +		return -1;
      +	}
      +
      +	put_be16(s.buf, r->tz_offset);
     -+	s.buf += 2;
     -+	s.len -= 2;
     ++	slice_consume(&s, 2);
      +
      +	n = encode_string(r->message ? r->message : "", s);
      +	if (n < 0) {
      +		return -1;
      +	}
     -+	s.len -= n;
     -+	s.buf += n;
     ++	slice_consume(&s, n);
      +
      +	return start.len - s.len;
      +}
      +
     -+static int log_record_decode(void *rec, struct slice key, byte val_type,
     -+			     struct slice in, int hash_size)
     ++static int reftable_log_record_decode(void *rec, struct slice key,
     ++				      byte val_type, struct slice in,
     ++				      int hash_size)
      +{
      +	struct slice start = in;
     -+	struct log_record *r = (struct log_record *)rec;
     ++	struct reftable_log_record *r = (struct reftable_log_record *)rec;
      +	uint64_t max = 0;
      +	uint64_t ts = 0;
      +	struct slice dest = { 0 };
     @@ -3386,33 +3483,35 @@
      +		return FORMAT_ERROR;
      +	}
      +
     -+	r->ref_name = realloc(r->ref_name, key.len - 8);
     ++	r->ref_name = reftable_realloc(r->ref_name, key.len - 8);
      +	memcpy(r->ref_name, key.buf, key.len - 8);
      +	ts = get_be64(key.buf + key.len - 8);
      +
      +	r->update_index = (~max) - ts;
      +
     ++	if (val_type == 0) {
     ++		return 0;
     ++	}
     ++
      +	if (in.len < 2 * hash_size) {
      +		return FORMAT_ERROR;
      +	}
      +
     -+	r->old_hash = realloc(r->old_hash, hash_size);
     -+	r->new_hash = realloc(r->new_hash, hash_size);
     ++	r->old_hash = reftable_realloc(r->old_hash, hash_size);
     ++	r->new_hash = reftable_realloc(r->new_hash, hash_size);
      +
      +	memcpy(r->old_hash, in.buf, hash_size);
      +	memcpy(r->new_hash, in.buf + hash_size, hash_size);
      +
     -+	in.buf += 2 * hash_size;
     -+	in.len -= 2 * hash_size;
     ++	slice_consume(&in, 2 * hash_size);
      +
      +	n = decode_string(&dest, in);
      +	if (n < 0) {
      +		goto error;
      +	}
     -+	in.len -= n;
     -+	in.buf += n;
     ++	slice_consume(&in, n);
      +
     -+	r->name = realloc(r->name, dest.len + 1);
     ++	r->name = reftable_realloc(r->name, dest.len + 1);
      +	memcpy(r->name, dest.buf, dest.len);
      +	r->name[dest.len] = 0;
      +
     @@ -3421,10 +3520,9 @@
      +	if (n < 0) {
      +		goto error;
      +	}
     -+	in.len -= n;
     -+	in.buf += n;
     ++	slice_consume(&in, n);
      +
     -+	r->email = realloc(r->email, dest.len + 1);
     ++	r->email = reftable_realloc(r->email, dest.len + 1);
      +	memcpy(r->email, dest.buf, dest.len);
      +	r->email[dest.len] = 0;
      +
     @@ -3433,33 +3531,30 @@
      +	if (n < 0) {
      +		goto error;
      +	}
     -+	in.len -= n;
     -+	in.buf += n;
     ++	slice_consume(&in, n);
      +	r->time = ts;
      +	if (in.len < 2) {
      +		goto error;
      +	}
      +
      +	r->tz_offset = get_be16(in.buf);
     -+	in.buf += 2;
     -+	in.len -= 2;
     ++	slice_consume(&in, 2);
      +
      +	slice_resize(&dest, 0);
      +	n = decode_string(&dest, in);
      +	if (n < 0) {
      +		goto error;
      +	}
     -+	in.len -= n;
     -+	in.buf += n;
     ++	slice_consume(&in, n);
      +
     -+	r->message = realloc(r->message, dest.len + 1);
     ++	r->message = reftable_realloc(r->message, dest.len + 1);
      +	memcpy(r->message, dest.buf, dest.len);
      +	r->message[dest.len] = 0;
      +
      +	return start.len - in.len;
      +
      +error:
     -+	free(slice_yield(&dest));
     ++	reftable_free(slice_yield(&dest));
      +	return FORMAT_ERROR;
      +}
      +
     @@ -3486,7 +3581,8 @@
      +	return !memcmp(a, b, sz);
      +}
      +
     -+bool log_record_equal(struct log_record *a, struct log_record *b, int hash_size)
     ++bool reftable_log_record_equal(struct reftable_log_record *a,
     ++			       struct reftable_log_record *b, int hash_size)
      +{
      +	return null_streq(a->name, b->name) && null_streq(a->email, b->email) &&
      +	       null_streq(a->message, b->message) &&
     @@ -3496,14 +3592,14 @@
      +	       a->update_index == b->update_index;
      +}
      +
     -+struct record_vtable log_record_vtable = {
     -+	.key = &log_record_key,
     -+	.type = &log_record_type,
     -+	.copy_from = &log_record_copy_from,
     -+	.val_type = &log_record_val_type,
     -+	.encode = &log_record_encode,
     -+	.decode = &log_record_decode,
     -+	.clear = &log_record_clear_void,
     ++struct record_vtable reftable_log_record_vtable = {
     ++	.key = &reftable_log_record_key,
     ++	.type = &reftable_log_record_type,
     ++	.copy_from = &reftable_log_record_copy_from,
     ++	.val_type = &reftable_log_record_val_type,
     ++	.encode = &reftable_log_record_encode,
     ++	.decode = &reftable_log_record_decode,
     ++	.clear = &reftable_log_record_clear_void,
      +};
      +
      +struct record new_record(byte typ)
     @@ -3511,23 +3607,27 @@
      +	struct record rec;
      +	switch (typ) {
      +	case BLOCK_TYPE_REF: {
     -+		struct ref_record *r = calloc(1, sizeof(struct ref_record));
     ++		struct reftable_ref_record *r =
     ++			reftable_calloc(sizeof(struct reftable_ref_record));
      +		record_from_ref(&rec, r);
      +		return rec;
      +	}
      +
      +	case BLOCK_TYPE_OBJ: {
     -+		struct obj_record *r = calloc(1, sizeof(struct obj_record));
     ++		struct obj_record *r =
     ++			reftable_calloc(sizeof(struct obj_record));
      +		record_from_obj(&rec, r);
      +		return rec;
      +	}
      +	case BLOCK_TYPE_LOG: {
     -+		struct log_record *r = calloc(1, sizeof(struct log_record));
     ++		struct reftable_log_record *r =
     ++			reftable_calloc(sizeof(struct reftable_log_record));
      +		record_from_log(&rec, r);
      +		return rec;
      +	}
      +	case BLOCK_TYPE_INDEX: {
     -+		struct index_record *r = calloc(1, sizeof(struct index_record));
     ++		struct index_record *r =
     ++			reftable_calloc(sizeof(struct index_record));
      +		record_from_index(&rec, r);
      +		return rec;
      +	}
     @@ -3560,7 +3660,7 @@
      +static void index_record_clear(void *rec)
      +{
      +	struct index_record *idx = (struct index_record *)rec;
     -+	free(slice_yield(&idx->last_key));
     ++	reftable_free(slice_yield(&idx->last_key));
      +}
      +
      +static byte index_record_val_type(const void *rec)
     @@ -3578,8 +3678,7 @@
      +		return n;
      +	}
      +
     -+	out.buf += n;
     -+	out.len -= n;
     ++	slice_consume(&out, n);
      +
      +	return start.len - out.len;
      +}
     @@ -3598,8 +3697,7 @@
      +		return n;
      +	}
      +
     -+	in.buf += n;
     -+	in.len -= n;
     ++	slice_consume(&in, n);
      +	return start.len - in.len;
      +}
      +
     @@ -3651,10 +3749,10 @@
      +	return rec.ops->clear(rec.data);
      +}
      +
     -+void record_from_ref(struct record *rec, struct ref_record *ref_rec)
     ++void record_from_ref(struct record *rec, struct reftable_ref_record *ref_rec)
      +{
      +	rec->data = ref_rec;
     -+	rec->ops = &ref_record_vtable;
     ++	rec->ops = &reftable_ref_record_vtable;
      +}
      +
      +void record_from_obj(struct record *rec, struct obj_record *obj_rec)
     @@ -3669,10 +3767,10 @@
      +	rec->ops = &index_record_vtable;
      +}
      +
     -+void record_from_log(struct record *rec, struct log_record *log_rec)
     ++void record_from_log(struct record *rec, struct reftable_log_record *log_rec)
      +{
      +	rec->data = log_rec;
     -+	rec->ops = &log_record_vtable;
     ++	rec->ops = &reftable_log_record_vtable;
      +}
      +
      +void *record_yield(struct record *rec)
     @@ -3682,10 +3780,10 @@
      +	return p;
      +}
      +
     -+struct ref_record *record_as_ref(struct record rec)
     ++struct reftable_ref_record *record_as_ref(struct record rec)
      +{
      +	assert(record_type(rec) == BLOCK_TYPE_REF);
     -+	return (struct ref_record *)rec.data;
     ++	return (struct reftable_ref_record *)rec.data;
      +}
      +
      +static bool hash_equal(byte *a, byte *b, int hash_size)
     @@ -3706,7 +3804,8 @@
      +	return a == b;
      +}
      +
     -+bool ref_record_equal(struct ref_record *a, struct ref_record *b, int hash_size)
     ++bool reftable_ref_record_equal(struct reftable_ref_record *a,
     ++			       struct reftable_ref_record *b, int hash_size)
      +{
      +	assert(hash_size > 0);
      +	return 0 == strcmp(a->ref_name, b->ref_name) &&
     @@ -3716,22 +3815,22 @@
      +	       str_equal(a->target, b->target);
      +}
      +
     -+int ref_record_compare_name(const void *a, const void *b)
     ++int reftable_ref_record_compare_name(const void *a, const void *b)
      +{
     -+	return strcmp(((struct ref_record *)a)->ref_name,
     -+		      ((struct ref_record *)b)->ref_name);
     ++	return strcmp(((struct reftable_ref_record *)a)->ref_name,
     ++		      ((struct reftable_ref_record *)b)->ref_name);
      +}
      +
     -+bool ref_record_is_deletion(const struct ref_record *ref)
     ++bool reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
      +{
      +	return ref->value == NULL && ref->target == NULL &&
      +	       ref->target_value == NULL;
      +}
      +
     -+int log_record_compare_key(const void *a, const void *b)
     ++int reftable_log_record_compare_key(const void *a, const void *b)
      +{
     -+	struct log_record *la = (struct log_record *)a;
     -+	struct log_record *lb = (struct log_record *)b;
     ++	struct reftable_log_record *la = (struct reftable_log_record *)a;
     ++	struct reftable_log_record *lb = (struct reftable_log_record *)b;
      +
      +	int cmp = strcmp(la->ref_name, lb->ref_name);
      +	if (cmp) {
     @@ -3743,10 +3842,12 @@
      +	return (la->update_index < lb->update_index) ? 1 : 0;
      +}
      +
     -+bool log_record_is_deletion(const struct log_record *log)
     ++bool reftable_log_record_is_deletion(const struct reftable_log_record *log)
      +{
     -+	/* XXX */
     -+	return false;
     ++	return (log->new_hash == NULL && log->old_hash == NULL &&
     ++		log->name == NULL && log->email == NULL &&
     ++		log->message == NULL && log->time == 0 && log->tz_offset == 0 &&
     ++		log->message == NULL);
      +}
      +
      +int hash_size(uint32_t id)
     @@ -3780,14 +3881,33 @@
      +#include "reftable.h"
      +#include "slice.h"
      +
     ++/* utilities for de/encoding varints */
     ++
     ++int get_var_int(uint64_t *dest, struct slice in);
     ++int put_var_int(struct slice dest, uint64_t val);
     ++
     ++/* Methods for records. */
      +struct record_vtable {
     ++	/* encode the key of to a byte slice. */
      +	void (*key)(const void *rec, struct slice *dest);
     ++
     ++	/* The record type of ('r' for ref). */
      +	byte (*type)(void);
     -+	void (*copy_from)(void *rec, const void *src, int hash_size);
     ++
     ++	void (*copy_from)(void *dest, const void *src, int hash_size);
     ++
     ++	/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
     ++	 * vs ref deletion) */
      +	byte (*val_type)(const void *rec);
     ++
     ++	/* encodes rec into dest, returning how much space was used. */
      +	int (*encode)(const void *rec, struct slice dest, int hash_size);
     ++
     ++	/* decode data from `src` into the record. */
      +	int (*decode)(void *rec, struct slice key, byte extra, struct slice src,
      +		      int hash_size);
     ++
     ++	/* deallocate and null the record. */
      +	void (*clear)(void *rec);
      +};
      +
     @@ -3797,32 +3917,34 @@
      +	struct record_vtable *ops;
      +};
      +
     -+int get_var_int(uint64_t *dest, struct slice in);
     -+int put_var_int(struct slice dest, uint64_t val);
     -+int common_prefix_size(struct slice a, struct slice b);
     -+
      +int is_block_type(byte typ);
     ++
      +struct record new_record(byte typ);
      +
     -+extern struct record_vtable ref_record_vtable;
     ++extern struct record_vtable reftable_ref_record_vtable;
      +
      +int encode_key(bool *restart, struct slice dest, struct slice prev_key,
      +	       struct slice key, byte extra);
      +int decode_key(struct slice *key, byte *extra, struct slice last_key,
      +	       struct slice in);
      +
     ++/* index_record are used internally to speed up lookups. */
      +struct index_record {
     -+	uint64_t offset;
     -+	struct slice last_key;
     ++	uint64_t offset; /* Offset of block */
     ++	struct slice last_key; /* Last key of the block. */
      +};
      +
     ++/* obj_record stores an object ID => ref mapping. */
      +struct obj_record {
     -+	byte *hash_prefix;
     -+	int hash_prefix_len;
     -+	uint64_t *offsets;
     ++	byte *hash_prefix; /* leading bytes of the object ID */
     ++	int hash_prefix_len; /* number of leading bytes. Constant
     ++			      * across a single table. */
     ++	uint64_t *offsets; /* a vector of file offsets. */
      +	int offset_len;
      +};
      +
     ++/* see struct record_vtable */
     ++
      +void record_key(struct record rec, struct slice *dest);
      +byte record_type(struct record rec);
      +void record_copy_from(struct record rec, struct record src, int hash_size);
     @@ -3831,18 +3953,24 @@
      +int record_decode(struct record rec, struct slice key, byte extra,
      +		  struct slice src, int hash_size);
      +void record_clear(struct record rec);
     ++
     ++/* clear out the record, yielding the record data that was encapsulated. */
      +void *record_yield(struct record *rec);
     ++
     ++/* initialize generic records from concrete records. The generic record should
     ++ * be zeroed out. */
     ++
      +void record_from_obj(struct record *rec, struct obj_record *objrec);
      +void record_from_index(struct record *rec, struct index_record *idxrec);
     -+void record_from_ref(struct record *rec, struct ref_record *refrec);
     -+void record_from_log(struct record *rec, struct log_record *logrec);
     -+struct ref_record *record_as_ref(struct record ref);
     ++void record_from_ref(struct record *rec, struct reftable_ref_record *refrec);
     ++void record_from_log(struct record *rec, struct reftable_log_record *logrec);
     ++struct reftable_ref_record *record_as_ref(struct record ref);
      +
      +/* for qsort. */
     -+int ref_record_compare_name(const void *a, const void *b);
     ++int reftable_ref_record_compare_name(const void *a, const void *b);
      +
      +/* for qsort. */
     -+int log_record_compare_key(const void *a, const void *b);
     ++int reftable_log_record_compare_key(const void *a, const void *b);
      +
      +#endif
      
     @@ -3863,65 +3991,20 @@
      +#define REFTABLE_H
      +
      +#include <stdint.h>
     ++#include <stddef.h>
      +
     -+/* block_source is a generic wrapper for a seekable readable file.
     -+   It is generally passed around by value.
     -+ */
     -+struct block_source {
     -+	struct block_source_vtable *ops;
     -+	void *arg;
     -+};
     ++void reftable_set_alloc(void *(*malloc)(size_t),
     ++			void *(*realloc)(void *, size_t), void (*free)(void *));
      +
     -+/* a contiguous segment of bytes. It keeps track of its generating block_source
     -+   so it can return itself into the pool.
     -+*/
     -+struct block {
     -+	uint8_t *data;
     -+	int len;
     -+	struct block_source source;
     -+};
     ++/****************************************************************
     ++ Basic data types
      +
     -+/* block_source_vtable are the operations that make up block_source */
     -+struct block_source_vtable {
     -+	/* returns the size of a block source */
     -+	uint64_t (*size)(void *source);
     ++ Reftables store the state of each ref in struct reftable_ref_record, and they
     ++ store a sequence of reflog updates in struct reftable_log_record.
     ++ ****************************************************************/
      +
     -+	/* reads a segment from the block source. It is an error to read
     -+	   beyond the end of the block */
     -+	int (*read_block)(void *source, struct block *dest, uint64_t off,
     -+			  uint32_t size);
     -+	/* mark the block as read; may return the data back to malloc */
     -+	void (*return_block)(void *source, struct block *blockp);
     -+
     -+	/* release all resources associated with the block source */
     -+	void (*close)(void *source);
     -+};
     -+
     -+/* opens a file on the file system as a block_source */
     -+int block_source_from_file(struct block_source *block_src, const char *name);
     -+
     -+/* write_options sets options for writing a single reftable. */
     -+struct write_options {
     -+	/* boolean: do not pad out blocks to block size. */
     -+	int unpadded;
     -+
     -+	/* the blocksize. Should be less than 2^24. */
     -+	uint32_t block_size;
     -+
     -+	/* boolean: do not generate a SHA1 => ref index. */
     -+	int skip_index_objects;
     -+
     -+	/* how often to write complete keys in each block. */
     -+	int restart_interval;
     -+
     -+	/* 4-byte identifier ("sha1", "s256") of the hash.
     -+	 * Defaults to SHA1 if unset
     -+	 */
     -+	uint32_t hash_id;
     -+};
     -+
     -+/* ref_record holds a ref database entry target_value */
     -+struct ref_record {
     ++/* reftable_ref_record holds a ref database entry target_value */
     ++struct reftable_ref_record {
      +	char *ref_name; /* Name of the ref, malloced. */
      +	uint64_t update_index; /* Logical timestamp at which this value is
      +				  written */
     @@ -3931,21 +4014,23 @@
      +};
      +
      +/* returns whether 'ref' represents a deletion */
     -+int ref_record_is_deletion(const struct ref_record *ref);
     ++int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
      +
     -+/* prints a ref_record onto stdout */
     -+void ref_record_print(struct ref_record *ref, int hash_size);
     ++/* prints a reftable_ref_record onto stdout */
     ++void reftable_ref_record_print(struct reftable_ref_record *ref, int hash_size);
      +
      +/* frees and nulls all pointer values. */
     -+void ref_record_clear(struct ref_record *ref);
     ++void reftable_ref_record_clear(struct reftable_ref_record *ref);
      +
     -+/* returns whether two ref_records are the same */
     -+int ref_record_equal(struct ref_record *a, struct ref_record *b, int hash_size);
     ++/* returns whether two reftable_ref_records are the same */
     ++int reftable_ref_record_equal(struct reftable_ref_record *a,
     ++			      struct reftable_ref_record *b, int hash_size);
      +
     -+/* log_record holds a reflog entry */
     -+struct log_record {
     ++/* reftable_log_record holds a reflog entry */
     ++struct reftable_log_record {
      +	char *ref_name;
     -+	uint64_t update_index;
     ++	uint64_t update_index; /* logical timestamp of a transactional update.
     ++				*/
      +	uint8_t *new_hash;
      +	uint8_t *old_hash;
      +	char *name;
     @@ -3956,39 +4041,88 @@
      +};
      +
      +/* returns whether 'ref' represents the deletion of a log record. */
     -+int log_record_is_deletion(const struct log_record *log);
     ++int reftable_log_record_is_deletion(const struct reftable_log_record *log);
      +
      +/* frees and nulls all pointer values. */
     -+void log_record_clear(struct log_record *log);
     ++void reftable_log_record_clear(struct reftable_log_record *log);
      +
      +/* returns whether two records are equal. */
     -+int log_record_equal(struct log_record *a, struct log_record *b, int hash_size);
     ++int reftable_log_record_equal(struct reftable_log_record *a,
     ++			      struct reftable_log_record *b, int hash_size);
      +
     -+void log_record_print(struct log_record *log, int hash_size);
     ++/* dumps a reftable_log_record on stdout, for debugging/testing. */
     ++void reftable_log_record_print(struct reftable_log_record *log, int hash_size);
      +
     -+/* iterator is the generic interface for walking over data stored in a
     -+   reftable. It is generally passed around by value.
     -+*/
     -+struct iterator {
     -+	struct iterator_vtable *ops;
     -+	void *iter_arg;
     ++/****************************************************************
     ++ Error handling
     ++
     ++ Error are signaled with negative integer return values. 0 means success.
     ++ ****************************************************************/
     ++
     ++/* different types of errors */
     ++enum reftable_error {
     ++	/* Unexpected file system behavior */
     ++	IO_ERROR = -2,
     ++
     ++	/* Format inconsistency on reading data
     ++	 */
     ++	FORMAT_ERROR = -3,
     ++
     ++	/* File does not exist. Returned from block_source_from_file(),  because
     ++	   it needs special handling in stack.
     ++	*/
     ++	NOT_EXIST_ERROR = -4,
     ++
     ++	/* Trying to write out-of-date data. */
     ++	LOCK_ERROR = -5,
     ++
     ++	/* Misuse of the API:
     ++	   - on writing a record with NULL ref_name.
     ++	   - on writing a reftable_ref_record outside the table limits
     ++	   - on writing a ref or log record before the stack's next_update_index
     ++	   - on reading a reftable_ref_record from log iterator, or vice versa.
     ++	*/
     ++	API_ERROR = -6,
     ++
     ++	/* Decompression error */
     ++	ZLIB_ERROR = -7,
     ++
     ++	/* Wrote a table without blocks. */
     ++	EMPTY_TABLE_ERROR = -8,
      +};
      +
     -+/* reads the next ref_record. Returns < 0 for error, 0 for OK and > 0:
     -+   end of iteration.
     -+*/
     -+int iterator_next_ref(struct iterator it, struct ref_record *ref);
     ++/* convert the numeric error code to a string. The string should not be
     ++ * deallocated. */
     ++const char *reftable_error_str(int err);
      +
     -+/* reads the next log_record. Returns < 0 for error, 0 for OK and > 0:
     -+   end of iteration.
     -+*/
     -+int iterator_next_log(struct iterator it, struct log_record *log);
     ++/****************************************************************
     ++ Writing
      +
     -+/* releases resources associated with an iterator. */
     -+void iterator_destroy(struct iterator *it);
     ++ Writing single reftables
     ++ ****************************************************************/
     ++
     ++/* reftable_write_options sets options for writing a single reftable. */
     ++struct reftable_write_options {
     ++	/* boolean: do not pad out blocks to block size. */
     ++	int unpadded;
     ++
     ++	/* the blocksize. Should be less than 2^24. */
     ++	uint32_t block_size;
      +
     -+/* block_stats holds statistics for a single block type */
     -+struct block_stats {
     ++	/* boolean: do not generate a SHA1 => ref index. */
     ++	int skip_index_objects;
     ++
     ++	/* how often to write complete keys in each block. */
     ++	int restart_interval;
     ++
     ++	/* 4-byte identifier ("sha1", "s256") of the hash.
     ++	 * Defaults to SHA1 if unset
     ++	 */
     ++	uint32_t hash_id;
     ++};
     ++
     ++/* reftable_block_stats holds statistics for a single block type */
     ++struct reftable_block_stats {
      +	/* total number of entries written */
      +	int entries;
      +	/* total number of key restarts */
     @@ -4008,119 +4142,175 @@
      +};
      +
      +/* stats holds overall statistics for a single reftable */
     -+struct stats {
     ++struct reftable_stats {
      +	/* total number of blocks written. */
      +	int blocks;
      +	/* stats for ref data */
     -+	struct block_stats ref_stats;
     ++	struct reftable_block_stats ref_stats;
      +	/* stats for the SHA1 to ref map. */
     -+	struct block_stats obj_stats;
     ++	struct reftable_block_stats obj_stats;
      +	/* stats for index blocks */
     -+	struct block_stats idx_stats;
     ++	struct reftable_block_stats idx_stats;
      +	/* stats for log blocks */
     -+	struct block_stats log_stats;
     ++	struct reftable_block_stats log_stats;
      +
      +	/* disambiguation length of shortened object IDs. */
      +	int object_id_len;
      +};
      +
     -+/* different types of errors */
     -+
     -+/* Unexpected file system behavior */
     -+#define IO_ERROR -2
     -+
     -+/* Format inconsistency on reading data
     -+ */
     -+#define FORMAT_ERROR -3
     -+
     -+/* File does not exist. Returned from block_source_from_file(),  because it
     -+   needs special handling in stack.
     -+*/
     -+#define NOT_EXIST_ERROR -4
     -+
     -+/* Trying to write out-of-date data. */
     -+#define LOCK_ERROR -5
     -+
     -+/* Misuse of the API:
     -+   - on writing a record with NULL ref_name.
     -+   - on writing a ref_record outside the table limits
     -+   - on writing a ref or log record before the stack's next_update_index
     -+   - on reading a ref_record from log iterator, or vice versa.
     -+ */
     -+#define API_ERROR -6
     -+
     -+/* Decompression error */
     -+#define ZLIB_ERROR -7
     -+
     -+/* Wrote a table without blocks. */
     -+#define EMPTY_TABLE_ERROR -8
     -+
     -+const char *error_str(int err);
     -+
     -+/* new_writer creates a new writer */
     -+struct writer *new_writer(int (*writer_func)(void *, uint8_t *, int),
     -+			  void *writer_arg, struct write_options *opts);
     ++/* reftable_new_writer creates a new writer */
     ++struct reftable_writer *
     ++reftable_new_writer(int (*writer_func)(void *, uint8_t *, int),
     ++		    void *writer_arg, struct reftable_write_options *opts);
      +
      +/* write to a file descriptor. fdp should be an int* pointing to the fd. */
     -+int fd_writer(void *fdp, uint8_t *data, int size);
     ++int reftable_fd_write(void *fdp, uint8_t *data, int size);
      +
      +/* Set the range of update indices for the records we will add.  When
      +   writing a table into a stack, the min should be at least
     -+   stack_next_update_index(), or API_ERROR is returned.
     ++   reftable_stack_next_update_index(), or API_ERROR is returned.
     ++
     ++   For transactional updates, typically min==max. When converting an existing
     ++   ref database into a single reftable, this would be a range of update-index
     ++   timestamps.
      + */
     -+void writer_set_limits(struct writer *w, uint64_t min, uint64_t max);
     ++void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
     ++				uint64_t max);
      +
     -+/* adds a ref_record. Must be called in ascending
     ++/* adds a reftable_ref_record. Must be called in ascending
      +   order. The update_index must be within the limits set by
     -+   writer_set_limits(), or API_ERROR is returned.
     ++   reftable_writer_set_limits(), or API_ERROR is returned.
     ++
     ++   It is an error to write a ref record after a log record.
      + */
     -+int writer_add_ref(struct writer *w, struct ref_record *ref);
     ++int reftable_writer_add_ref(struct reftable_writer *w,
     ++			    struct reftable_ref_record *ref);
      +
      +/* Convenience function to add multiple refs. Will sort the refs by
      +   name before adding. */
     -+int writer_add_refs(struct writer *w, struct ref_record *refs, int n);
     ++int reftable_writer_add_refs(struct reftable_writer *w,
     ++			     struct reftable_ref_record *refs, int n);
      +
     -+/* adds a log_record. Must be called in ascending order (with more
     ++/* adds a reftable_log_record. Must be called in ascending order (with more
      +   recent log entries first.)
      + */
     -+int writer_add_log(struct writer *w, struct log_record *log);
     ++int reftable_writer_add_log(struct reftable_writer *w,
     ++			    struct reftable_log_record *log);
      +
      +/* Convenience function to add multiple logs. Will sort the records by
      +   key before adding. */
     -+int writer_add_logs(struct writer *w, struct log_record *logs, int n);
     ++int reftable_writer_add_logs(struct reftable_writer *w,
     ++			     struct reftable_log_record *logs, int n);
     ++
     ++/* reftable_writer_close finalizes the reftable. The writer is retained so
     ++ * statistics can be inspected. */
     ++int reftable_writer_close(struct reftable_writer *w);
     ++
     ++/* writer_stats returns the statistics on the reftable being written.
     ++
     ++   This struct becomes invalid when the writer is freed.
     ++ */
     ++const struct reftable_stats *writer_stats(struct reftable_writer *w);
     ++
     ++/* reftable_writer_free deallocates memory for the writer */
     ++void reftable_writer_free(struct reftable_writer *w);
     ++
     ++/****************************************************************
     ++ * ITERATING
     ++ ****************************************************************/
      +
     -+/* writer_close finalizes the reftable. The writer is retained so statistics can
     -+ * be inspected. */
     -+int writer_close(struct writer *w);
     ++/* iterator is the generic interface for walking over data stored in a
     ++   reftable. It is generally passed around by value.
     ++*/
     ++struct reftable_iterator {
     ++	struct reftable_iterator_vtable *ops;
     ++	void *iter_arg;
     ++};
      +
     -+/* writer_stats returns the statistics on the reftable being written. */
     -+struct stats *writer_stats(struct writer *w);
     ++/* reads the next reftable_ref_record. Returns < 0 for error, 0 for OK and > 0:
     ++   end of iteration.
     ++*/
     ++int reftable_iterator_next_ref(struct reftable_iterator it,
     ++			       struct reftable_ref_record *ref);
      +
     -+/* writer_free deallocates memory for the writer */
     -+void writer_free(struct writer *w);
     ++/* reads the next reftable_log_record. Returns < 0 for error, 0 for OK and > 0:
     ++   end of iteration.
     ++*/
     ++int reftable_iterator_next_log(struct reftable_iterator it,
     ++			       struct reftable_log_record *log);
      +
     -+struct reader;
     ++/* releases resources associated with an iterator. */
     ++void reftable_iterator_destroy(struct reftable_iterator *it);
     ++
     ++/****************************************************************
     ++ Reading single tables
      +
     -+/* new_reader opens a reftable for reading. If successful, returns 0
     ++ The follow routines are for reading single files. For an application-level
     ++ interface, skip ahead to struct reftable_merged_table and struct
     ++ reftable_stack.
     ++ ****************************************************************/
     ++
     ++/* block_source is a generic wrapper for a seekable readable file.
     ++   It is generally passed around by value.
     ++ */
     ++struct reftable_block_source {
     ++	struct reftable_block_source_vtable *ops;
     ++	void *arg;
     ++};
     ++
     ++/* a contiguous segment of bytes. It keeps track of its generating block_source
     ++   so it can return itself into the pool.
     ++*/
     ++struct reftable_block {
     ++	uint8_t *data;
     ++	int len;
     ++	struct reftable_block_source source;
     ++};
     ++
     ++/* block_source_vtable are the operations that make up block_source */
     ++struct reftable_block_source_vtable {
     ++	/* returns the size of a block source */
     ++	uint64_t (*size)(void *source);
     ++
     ++	/* reads a segment from the block source. It is an error to read
     ++	   beyond the end of the block */
     ++	int (*read_block)(void *source, struct reftable_block *dest,
     ++			  uint64_t off, uint32_t size);
     ++	/* mark the block as read; may return the data back to malloc */
     ++	void (*return_block)(void *source, struct reftable_block *blockp);
     ++
     ++	/* release all resources associated with the block source */
     ++	void (*close)(void *source);
     ++};
     ++
     ++/* opens a file on the file system as a block_source */
     ++int reftable_block_source_from_file(struct reftable_block_source *block_src,
     ++				    const char *name);
     ++
     ++/* The reader struct is a handle to an open reftable file. */
     ++struct reftable_reader;
     ++
     ++/* reftable_new_reader opens a reftable for reading. If successful, returns 0
      + * code and sets pp.  The name is used for creating a
      + * stack. Typically, it is the basename of the file.
      + */
     -+int new_reader(struct reader **pp, struct block_source, const char *name);
     ++int reftable_new_reader(struct reftable_reader **pp,
     ++			struct reftable_block_source, const char *name);
      +
     -+/* reader_seek_ref returns an iterator where 'name' would be inserted in the
     -+   table.
     ++/* reftable_reader_seek_ref returns an iterator where 'name' would be inserted
     ++   in the table.  To seek to the start of the table, use name = "".
      +
      +   example:
      +
     -+   struct reader *r = NULL;
     -+   int err = new_reader(&r, src, "filename");
     ++   struct reftable_reader *r = NULL;
     ++   int err = reftable_new_reader(&r, src, "filename");
      +   if (err < 0) { ... }
     -+   struct iterator it  = {0};
     -+   err = reader_seek_ref(r, &it, "refs/heads/master");
     ++   struct reftable_iterator it  = {0};
     ++   err = reftable_reader_seek_ref(r, &it, "refs/heads/master");
      +   if (err < 0) { ... }
     -+   struct ref_record ref  = {0};
     ++   struct reftable_ref_record ref  = {0};
      +   while (1) {
     -+     err = iterator_next_ref(it, &ref);
     ++     err = reftable_iterator_next_ref(it, &ref);
      +     if (err > 0) {
      +       break;
      +     }
     @@ -4129,103 +4319,149 @@
      +     }
      +     ..found..
      +   }
     -+   iterator_destroy(&it);
     -+   ref_record_clear(&ref);
     ++   reftable_iterator_destroy(&it);
     ++   reftable_ref_record_clear(&ref);
      + */
     -+int reader_seek_ref(struct reader *r, struct iterator *it, const char *name);
     ++int reftable_reader_seek_ref(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, const char *name);
      +
      +/* returns the hash ID used in this table. */
     -+uint32_t reader_hash_id(struct reader *r);
     ++uint32_t reftable_reader_hash_id(struct reftable_reader *r);
      +
     -+/* seek to logs for the given name, older than update_index. */
     -+int reader_seek_log_at(struct reader *r, struct iterator *it, const char *name,
     -+		       uint64_t update_index);
     ++/* seek to logs for the given name, older than update_index. To seek to the
     ++   start of the table, use name = "".
     ++ */
     ++int reftable_reader_seek_log_at(struct reftable_reader *r,
     ++				struct reftable_iterator *it, const char *name,
     ++				uint64_t update_index);
      +
      +/* seek to newest log entry for given name. */
     -+int reader_seek_log(struct reader *r, struct iterator *it, const char *name);
     ++int reftable_reader_seek_log(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, const char *name);
      +
      +/* closes and deallocates a reader. */
     -+void reader_free(struct reader *);
     ++void reftable_reader_free(struct reftable_reader *);
      +
      +/* return an iterator for the refs pointing to oid */
     -+int reader_refs_for(struct reader *r, struct iterator *it, uint8_t *oid,
     -+		    int oid_len);
     ++int reftable_reader_refs_for(struct reftable_reader *r,
     ++			     struct reftable_iterator *it, uint8_t *oid,
     ++			     int oid_len);
      +
      +/* return the max_update_index for a table */
     -+uint64_t reader_max_update_index(struct reader *r);
     ++uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
      +
      +/* return the min_update_index for a table */
     -+uint64_t reader_min_update_index(struct reader *r);
     ++uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
     ++
     ++/****************************************************************
     ++ Merged tables
      +
     -+/* a merged table is implements seeking/iterating over a stack of tables. */
     -+struct merged_table;
     ++ A ref database kept in a sequence of table files. The merged_table presents a
     ++ unified view to reading (seeking, iterating) a sequence of immutable tables.
     ++ ****************************************************************/
      +
     -+/* new_merged_table creates a new merged table. It takes ownership of the stack
     -+   array.
     ++/* A merged table is implements seeking/iterating over a stack of tables. */
     ++struct reftable_merged_table;
     ++
     ++/* reftable_new_merged_table creates a new merged table. It takes ownership of
     ++   the stack array.
      +*/
     -+int new_merged_table(struct merged_table **dest, struct reader **stack, int n,
     -+		     uint32_t hash_id);
     ++int reftable_new_merged_table(struct reftable_merged_table **dest,
     ++			      struct reftable_reader **stack, int n,
     ++			      uint32_t hash_id);
      +
      +/* returns the hash id used in this merged table. */
     -+uint32_t merged_hash_id(struct merged_table *mt);
     ++uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt);
      +
      +/* returns an iterator positioned just before 'name' */
     -+int merged_table_seek_ref(struct merged_table *mt, struct iterator *it,
     -+			  const char *name);
     ++int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
     ++				   struct reftable_iterator *it,
     ++				   const char *name);
      +
      +/* returns an iterator for log entry, at given update_index */
     -+int merged_table_seek_log_at(struct merged_table *mt, struct iterator *it,
     -+			     const char *name, uint64_t update_index);
     ++int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
     ++				      struct reftable_iterator *it,
     ++				      const char *name, uint64_t update_index);
      +
     -+/* like merged_table_seek_log_at but look for the newest entry. */
     -+int merged_table_seek_log(struct merged_table *mt, struct iterator *it,
     -+			  const char *name);
     ++/* like reftable_merged_table_seek_log_at but look for the newest entry. */
     ++int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
     ++				   struct reftable_iterator *it,
     ++				   const char *name);
      +
      +/* returns the max update_index covered by this merged table. */
     -+uint64_t merged_max_update_index(struct merged_table *mt);
     ++uint64_t
     ++reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
      +
      +/* returns the min update_index covered by this merged table. */
     -+uint64_t merged_min_update_index(struct merged_table *mt);
     ++uint64_t
     ++reftable_merged_table_min_update_index(struct reftable_merged_table *mt);
      +
      +/* closes readers for the merged tables */
     -+void merged_table_close(struct merged_table *mt);
     ++void reftable_merged_table_close(struct reftable_merged_table *mt);
      +
      +/* releases memory for the merged_table */
     -+void merged_table_free(struct merged_table *m);
     ++void reftable_merged_table_free(struct reftable_merged_table *m);
     ++
     ++/****************************************************************
     ++ Mutable ref database
     ++
     ++ The stack presents an interface to a mutable sequence of reftables.
     ++ ****************************************************************/
      +
      +/* a stack is a stack of reftables, which can be mutated by pushing a table to
      + * the top of the stack */
     -+struct stack;
     ++struct reftable_stack;
      +
     -+/* open a new reftable stack. The tables will be stored in 'dir', while the list
     -+   of tables is in 'list_file'. Typically, this should be .git/reftables and
     -+   .git/refs respectively.
     ++/* open a new reftable stack. The tables along with the table list will be
     ++   stored in 'dir'. Typically, this should be .git/reftables.
      +*/
     -+int new_stack(struct stack **dest, const char *dir, const char *list_file,
     -+	      struct write_options config);
     ++int reftable_new_stack(struct reftable_stack **dest, const char *dir,
     ++		       struct reftable_write_options config);
      +
      +/* returns the update_index at which a next table should be written. */
     -+uint64_t stack_next_update_index(struct stack *st);
     ++uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
     ++
     ++/* holds a transaction to add tables at the top of a stack. */
     ++struct reftable_addition;
     ++
     ++/*
     ++  returns a new transaction to add reftables to the given stack. As a side
     ++  effect, the ref database is locked.
     ++*/ 
     ++int reftable_stack_new_addition(struct reftable_addition **dest, struct reftable_stack *st);
     ++
     ++/* Adds a reftable to transaction. */ 
     ++int reftable_addition_add(struct reftable_addition *add,
     ++                          int (*write_table)(struct reftable_writer *wr, void *arg),
     ++                          void *arg);
     ++
     ++/* Commits the transaction, releasing the lock. */
     ++int reftable_addition_commit(struct reftable_addition *add);
     ++
     ++/* Release all non-committed data from the transaction; releases the lock if held. */
     ++void reftable_addition_close(struct reftable_addition *add);
      +
      +/* add a new table to the stack. The write_table function must call
     -+   writer_set_limits, add refs and return an error value. */
     -+int stack_add(struct stack *st,
     -+	      int (*write_table)(struct writer *wr, void *write_arg),
     -+	      void *write_arg);
     ++   reftable_writer_set_limits, add refs and return an error value. */
     ++int reftable_stack_add(struct reftable_stack *st,
     ++		       int (*write_table)(struct reftable_writer *wr,
     ++					  void *write_arg),
     ++		       void *write_arg);
      +
      +/* returns the merged_table for seeking. This table is valid until the
      +   next write or reload, and should not be closed or deleted.
      +*/
     -+struct merged_table *stack_merged_table(struct stack *st);
     ++struct reftable_merged_table *
     ++reftable_stack_merged_table(struct reftable_stack *st);
      +
      +/* frees all resources associated with the stack. */
     -+void stack_destroy(struct stack *st);
     ++void reftable_stack_destroy(struct reftable_stack *st);
      +
      +/* reloads the stack if necessary. */
     -+int stack_reload(struct stack *st);
     ++int reftable_stack_reload(struct reftable_stack *st);
      +
      +/* Policy for expiring reflog entries. */
     -+struct log_expiry_config {
     ++struct reftable_log_expiry_config {
      +	/* Drop entries older than this timestamp */
      +	uint64_t time;
      +
     @@ -4235,29 +4471,32 @@
      +
      +/* compacts all reftables into a giant table. Expire reflog entries if config is
      + * non-NULL */
     -+int stack_compact_all(struct stack *st, struct log_expiry_config *config);
     ++int reftable_stack_compact_all(struct reftable_stack *st,
     ++			       struct reftable_log_expiry_config *config);
      +
      +/* heuristically compact unbalanced table stack. */
     -+int stack_auto_compact(struct stack *st);
     ++int reftable_stack_auto_compact(struct reftable_stack *st);
      +
      +/* convenience function to read a single ref. Returns < 0 for error, 0
      +   for success, and 1 if ref not found. */
     -+int stack_read_ref(struct stack *st, const char *refname,
     -+		   struct ref_record *ref);
     ++int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
     ++			    struct reftable_ref_record *ref);
      +
      +/* convenience function to read a single log. Returns < 0 for error, 0
      +   for success, and 1 if ref not found. */
     -+int stack_read_log(struct stack *st, const char *refname,
     -+		   struct log_record *log);
     ++int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
     ++			    struct reftable_log_record *log);
      +
      +/* statistics on past compactions. */
     -+struct compaction_stats {
     -+	uint64_t bytes;
     -+	int attempts;
     -+	int failures;
     ++struct reftable_compaction_stats {
     ++	uint64_t bytes; /* total number of bytes written */
     ++	int attempts; /* how often we tried to compact */
     ++	int failures; /* failures happen on concurrent updates */
      +};
      +
     -+struct compaction_stats *stack_compaction_stats(struct stack *st);
     ++/* return statistics for compaction up till now. */
     ++struct reftable_compaction_stats *
     ++reftable_stack_compaction_stats(struct reftable_stack *st);
      +
      +#endif
      
     @@ -4304,7 +4543,7 @@
      +			c = l;
      +		}
      +		s->cap = c;
     -+		s->buf = realloc(s->buf, s->cap);
     ++		s->buf = reftable_realloc(s->buf, s->cap);
      +	}
      +	s->len = l;
      +}
     @@ -4325,6 +4564,12 @@
      +	memcpy(s->buf + end, a.buf, a.len);
      +}
      +
     ++void slice_consume(struct slice *s, int n)
     ++{
     ++	s->buf += n;
     ++	s->len -= n;
     ++}
     ++
      +byte *slice_yield(struct slice *s)
      +{
      +	byte *p = s->buf;
     @@ -4394,7 +4639,7 @@
      +		if (newcap < b->len + sz) {
      +			newcap = (b->len + sz);
      +		}
     -+		b->buf = realloc(b->buf, newcap);
     ++		b->buf = reftable_realloc(b->buf, newcap);
      +		b->cap = newcap;
      +	}
      +
     @@ -4413,57 +4658,71 @@
      +	return ((struct slice *)b)->len;
      +}
      +
     -+static void slice_return_block(void *b, struct block *dest)
     ++static void slice_return_block(void *b, struct reftable_block *dest)
      +{
      +	memset(dest->data, 0xff, dest->len);
     -+	free(dest->data);
     ++	reftable_free(dest->data);
      +}
      +
      +static void slice_close(void *b)
      +{
      +}
      +
     -+static int slice_read_block(void *v, struct block *dest, uint64_t off,
     ++static int slice_read_block(void *v, struct reftable_block *dest, uint64_t off,
      +			    uint32_t size)
      +{
      +	struct slice *b = (struct slice *)v;
      +	assert(off + size <= b->len);
     -+	dest->data = calloc(size, 1);
     ++	dest->data = reftable_calloc(size);
      +	memcpy(dest->data, b->buf + off, size);
      +	dest->len = size;
      +	return size;
      +}
      +
     -+struct block_source_vtable slice_vtable = {
     ++struct reftable_block_source_vtable slice_vtable = {
      +	.size = &slice_size,
      +	.read_block = &slice_read_block,
      +	.return_block = &slice_return_block,
      +	.close = &slice_close,
      +};
      +
     -+void block_source_from_slice(struct block_source *bs, struct slice *buf)
     ++void block_source_from_slice(struct reftable_block_source *bs,
     ++			     struct slice *buf)
      +{
      +	bs->ops = &slice_vtable;
      +	bs->arg = buf;
      +}
      +
     -+static void malloc_return_block(void *b, struct block *dest)
     ++static void malloc_return_block(void *b, struct reftable_block *dest)
      +{
      +	memset(dest->data, 0xff, dest->len);
     -+	free(dest->data);
     ++	reftable_free(dest->data);
      +}
      +
     -+struct block_source_vtable malloc_vtable = {
     ++struct reftable_block_source_vtable malloc_vtable = {
      +	.return_block = &malloc_return_block,
      +};
      +
     -+struct block_source malloc_block_source_instance = {
     ++struct reftable_block_source malloc_block_source_instance = {
      +	.ops = &malloc_vtable,
      +};
      +
     -+struct block_source malloc_block_source(void)
     ++struct reftable_block_source malloc_block_source(void)
      +{
      +	return malloc_block_source_instance;
     ++}
     ++
     ++int common_prefix_size(struct slice a, struct slice b)
     ++{
     ++	int p = 0;
     ++	while (p < a.len && p < b.len) {
     ++		if (a.buf[p] != b.buf[p]) {
     ++			break;
     ++		}
     ++		p++;
     ++	}
     ++
     ++	return p;
      +}
      
       diff --git a/reftable/slice.h b/reftable/slice.h
     @@ -4498,16 +4757,19 @@
      +bool slice_equal(struct slice a, struct slice b);
      +byte *slice_yield(struct slice *s);
      +void slice_copy(struct slice *dest, struct slice src);
     ++void slice_consume(struct slice *s, int n);
      +void slice_resize(struct slice *s, int l);
      +int slice_compare(struct slice a, struct slice b);
      +int slice_write(struct slice *b, byte *data, int sz);
      +int slice_write_void(void *b, byte *data, int sz);
      +void slice_append(struct slice *dest, struct slice add);
     ++int common_prefix_size(struct slice a, struct slice b);
      +
     -+struct block_source;
     -+void block_source_from_slice(struct block_source *bs, struct slice *buf);
     ++struct reftable_block_source;
     ++void block_source_from_slice(struct reftable_block_source *bs,
     ++			     struct slice *buf);
      +
     -+struct block_source malloc_block_source(void);
     ++struct reftable_block_source malloc_block_source(void);
      +
      +#endif
      
     @@ -4532,19 +4794,26 @@
      +#include "reftable.h"
      +#include "writer.h"
      +
     -+int new_stack(struct stack **dest, const char *dir, const char *list_file,
     -+	      struct write_options config)
     ++int reftable_new_stack(struct reftable_stack **dest, const char *dir,
     ++		       struct reftable_write_options config)
      +{
     -+	struct stack *p = calloc(sizeof(struct stack), 1);
     ++	struct reftable_stack *p =
     ++		reftable_calloc(sizeof(struct reftable_stack));
     ++	struct slice list_file_name = {};
      +	int err = 0;
      +	*dest = NULL;
     -+	p->list_file = xstrdup(list_file);
     ++
     ++	slice_set_string(&list_file_name, dir);
     ++	slice_append_string(&list_file_name, "/reftables.list");
     ++
     ++	p->list_file = slice_to_string(list_file_name);
     ++	reftable_free(slice_yield(&list_file_name));
      +	p->reftable_dir = xstrdup(dir);
      +	p->config = config;
      +
     -+	err = stack_reload(p);
     ++	err = reftable_stack_reload(p);
      +	if (err < 0) {
     -+		stack_destroy(p);
     ++		reftable_stack_destroy(p);
      +	} else {
      +		*dest = p;
      +	}
     @@ -4571,7 +4840,7 @@
      +		goto exit;
      +	}
      +
     -+	buf = malloc(size + 1);
     ++	buf = reftable_malloc(size + 1);
      +	if (fread(buf, 1, size, f) != size) {
      +		err = IO_ERROR;
      +		goto exit;
     @@ -4580,7 +4849,7 @@
      +
      +	parse_names(buf, size, namesp);
      +exit:
     -+	free(buf);
     ++	reftable_free(buf);
      +	return err;
      +}
      +
     @@ -4590,7 +4859,7 @@
      +	int err = 0;
      +	if (f == NULL) {
      +		if (errno == ENOENT) {
     -+			*namesp = calloc(sizeof(char *), 1);
     ++			*namesp = reftable_calloc(sizeof(char *));
      +			return 0;
      +		}
      +
     @@ -4601,30 +4870,33 @@
      +	return err;
      +}
      +
     -+struct merged_table *stack_merged_table(struct stack *st)
     ++struct reftable_merged_table *
     ++reftable_stack_merged_table(struct reftable_stack *st)
      +{
      +	return st->merged;
      +}
      +
      +/* Close and free the stack */
     -+void stack_destroy(struct stack *st)
     ++void reftable_stack_destroy(struct reftable_stack *st)
      +{
      +	if (st->merged == NULL) {
      +		return;
      +	}
      +
     -+	merged_table_close(st->merged);
     -+	merged_table_free(st->merged);
     ++	reftable_merged_table_close(st->merged);
     ++	reftable_merged_table_free(st->merged);
      +	st->merged = NULL;
      +
      +	FREE_AND_NULL(st->list_file);
      +	FREE_AND_NULL(st->reftable_dir);
     -+	free(st);
     ++	reftable_free(st);
      +}
      +
     -+static struct reader **stack_copy_readers(struct stack *st, int cur_len)
     ++static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
     ++						   int cur_len)
      +{
     -+	struct reader **cur = calloc(sizeof(struct reader *), cur_len);
     ++	struct reftable_reader **cur =
     ++		reftable_calloc(sizeof(struct reftable_reader *) * cur_len);
      +	int i = 0;
      +	for (i = 0; i < cur_len; i++) {
      +		cur[i] = st->merged->stack[i];
     @@ -4632,21 +4904,22 @@
      +	return cur;
      +}
      +
     -+static int stack_reload_once(struct stack *st, char **names, bool reuse_open)
     ++static int reftable_stack_reload_once(struct reftable_stack *st, char **names,
     ++				      bool reuse_open)
      +{
      +	int cur_len = st->merged == NULL ? 0 : st->merged->stack_len;
     -+	struct reader **cur = stack_copy_readers(st, cur_len);
     ++	struct reftable_reader **cur = stack_copy_readers(st, cur_len);
      +	int err = 0;
      +	int names_len = names_length(names);
     -+	struct reader **new_tables =
     -+		malloc(sizeof(struct reader *) * names_len);
     ++	struct reftable_reader **new_tables =
     ++		reftable_malloc(sizeof(struct reftable_reader *) * names_len);
      +	int new_tables_len = 0;
     -+	struct merged_table *new_merged = NULL;
     ++	struct reftable_merged_table *new_merged = NULL;
      +
      +	struct slice table_path = { 0 };
      +
      +	while (*names) {
     -+		struct reader *rd = NULL;
     ++		struct reftable_reader *rd = NULL;
      +		char *name = *names++;
      +
      +		/* this is linear; we assume compaction keeps the number of
     @@ -4661,18 +4934,18 @@
      +		}
      +
      +		if (rd == NULL) {
     -+			struct block_source src = { 0 };
     ++			struct reftable_block_source src = { 0 };
      +			slice_set_string(&table_path, st->reftable_dir);
      +			slice_append_string(&table_path, "/");
      +			slice_append_string(&table_path, name);
      +
     -+			err = block_source_from_file(
     ++			err = reftable_block_source_from_file(
      +				&src, slice_as_string(&table_path));
      +			if (err < 0) {
      +				goto exit;
      +			}
      +
     -+			err = new_reader(&rd, src, name);
     ++			err = reftable_new_reader(&rd, src, name);
      +			if (err < 0) {
      +				goto exit;
      +			}
     @@ -4682,8 +4955,8 @@
      +	}
      +
      +	/* success! */
     -+	err = new_merged_table(&new_merged, new_tables, new_tables_len,
     -+			       st->config.hash_id);
     ++	err = reftable_new_merged_table(&new_merged, new_tables, new_tables_len,
     ++					st->config.hash_id);
      +	if (err < 0) {
      +		goto exit;
      +	}
     @@ -4692,7 +4965,7 @@
      +	new_tables_len = 0;
      +	if (st->merged != NULL) {
      +		merged_table_clear(st->merged);
     -+		merged_table_free(st->merged);
     ++		reftable_merged_table_free(st->merged);
      +	}
      +	st->merged = new_merged;
      +
     @@ -4701,20 +4974,20 @@
      +		for (i = 0; i < cur_len; i++) {
      +			if (cur[i] != NULL) {
      +				reader_close(cur[i]);
     -+				reader_free(cur[i]);
     ++				reftable_reader_free(cur[i]);
      +			}
      +		}
      +	}
      +exit:
     -+	free(slice_yield(&table_path));
     ++	reftable_free(slice_yield(&table_path));
      +	{
      +		int i = 0;
      +		for (i = 0; i < new_tables_len; i++) {
      +			reader_close(new_tables[i]);
      +		}
      +	}
     -+	free(new_tables);
     -+	free(cur);
     ++	reftable_free(new_tables);
     ++	reftable_free(cur);
      +	return err;
      +}
      +
     @@ -4731,7 +5004,8 @@
      +	return udiff;
      +}
      +
     -+static int stack_reload_maybe_reuse(struct stack *st, bool reuse_open)
     ++static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
     ++					     bool reuse_open)
      +{
      +	struct timeval deadline = { 0 };
      +	int err = gettimeofday(&deadline, NULL);
     @@ -4763,7 +5037,7 @@
      +			free_names(names);
      +			return err;
      +		}
     -+		err = stack_reload_once(st, names, reuse_open);
     ++		err = reftable_stack_reload_once(st, names, reuse_open);
      +		if (err == 0) {
      +			free_names(names);
      +			break;
     @@ -4794,15 +5068,15 @@
      +	return 0;
      +}
      +
     -+int stack_reload(struct stack *st)
     ++int reftable_stack_reload(struct reftable_stack *st)
      +{
     -+	return stack_reload_maybe_reuse(st, true);
     ++	return reftable_stack_reload_maybe_reuse(st, true);
      +}
      +
      +/* -1 = error
      + 0 = up to date
      + 1 = changed. */
     -+static int stack_uptodate(struct stack *st)
     ++static int stack_uptodate(struct reftable_stack *st)
      +{
      +	char **names = NULL;
      +	int err = read_lines(st->list_file, &names);
     @@ -4833,18 +5107,19 @@
      +	return err;
      +}
      +
     -+int stack_add(struct stack *st, int (*write)(struct writer *wr, void *arg),
     -+	      void *arg)
     ++int reftable_stack_add(struct reftable_stack *st,
     ++		       int (*write)(struct reftable_writer *wr, void *arg),
     ++		       void *arg)
      +{
      +	int err = stack_try_add(st, write, arg);
      +	if (err < 0) {
      +		if (err == LOCK_ERROR) {
     -+			err = stack_reload(st);
     ++			err = reftable_stack_reload(st);
      +		}
      +		return err;
      +	}
      +
     -+	return stack_auto_compact(st);
     ++	return reftable_stack_auto_compact(st);
      +}
      +
      +static void format_name(struct slice *dest, uint64_t min, uint64_t max)
     @@ -4854,34 +5129,35 @@
      +	slice_set_string(dest, buf);
      +}
      +
     -+int stack_try_add(struct stack *st,
     -+		  int (*write_table)(struct writer *wr, void *arg), void *arg)
     ++struct reftable_addition {
     ++	int lock_file_fd;
     ++	struct slice lock_file_name;
     ++	struct reftable_stack *stack;
     ++	char **names;
     ++	char **new_tables;
     ++	int new_tables_len;
     ++	uint64_t next_update_index;
     ++};
     ++
     ++static int reftable_stack_init_addition(struct reftable_addition *add,
     ++					struct reftable_stack *st)
      +{
     -+	struct slice lock_name = { 0 };
     -+	struct slice temp_tab_name = { 0 };
     -+	struct slice tab_name = { 0 };
     -+	struct slice next_name = { 0 };
     -+	struct slice table_list = { 0 };
     -+	struct writer *wr = NULL;
      +	int err = 0;
     -+	int tab_fd = 0;
     -+	int lock_fd = 0;
     -+	uint64_t next_update_index = 0;
     ++	add->stack = st;
      +
     -+	slice_set_string(&lock_name, st->list_file);
     -+	slice_append_string(&lock_name, ".lock");
     ++	slice_set_string(&add->lock_file_name, st->list_file);
     ++	slice_append_string(&add->lock_file_name, ".lock");
      +
     -+	lock_fd = open(slice_as_string(&lock_name), O_EXCL | O_CREAT | O_WRONLY,
     -+		       0644);
     -+	if (lock_fd < 0) {
     ++	add->lock_file_fd = open(slice_as_string(&add->lock_file_name),
     ++				 O_EXCL | O_CREAT | O_WRONLY, 0644);
     ++	if (add->lock_file_fd < 0) {
      +		if (errno == EEXIST) {
      +			err = LOCK_ERROR;
     -+			goto exit;
     ++		} else {
     ++			err = IO_ERROR;
      +		}
     -+		err = IO_ERROR;
      +		goto exit;
      +	}
     -+
      +	err = stack_uptodate(st);
      +	if (err < 0) {
      +		goto exit;
     @@ -4892,29 +5168,160 @@
      +		goto exit;
      +	}
      +
     -+	next_update_index = stack_next_update_index(st);
     ++	add->next_update_index = reftable_stack_next_update_index(st);
     ++exit:
     ++	if (err) {
     ++		reftable_addition_close(add);
     ++	}
     ++	return err;
     ++}
     ++
     ++void reftable_addition_close(struct reftable_addition *add)
     ++{
     ++	int i = 0;
     ++	struct slice nm = {};
     ++	for (i = 0; i < add->new_tables_len; i++) {
     ++		slice_set_string(&nm, add->stack->list_file);
     ++		slice_append_string(&nm, "/");
     ++		slice_append_string(&nm, add->new_tables[i]);
     ++		unlink(slice_as_string(&nm));
     ++
     ++		reftable_free(add->new_tables[i]);
     ++		add->new_tables[i] = NULL;
     ++	}
     ++	reftable_free(add->new_tables);
     ++	add->new_tables = NULL;
     ++	add->new_tables_len = 0;
     ++
     ++	if (add->lock_file_fd > 0) {
     ++		close(add->lock_file_fd);
     ++		add->lock_file_fd = 0;
     ++	}
     ++	if (add->lock_file_name.len > 0) {
     ++		unlink(slice_as_string(&add->lock_file_name));
     ++		reftable_free(slice_yield(&add->lock_file_name));
     ++	}
     ++
     ++	free_names(add->names);
     ++	add->names = NULL;
     ++}
     ++
     ++int reftable_addition_commit(struct reftable_addition *add)
     ++{
     ++	struct slice table_list = { 0 };
     ++	int i = 0;
     ++	int err = 0;
     ++	if (add->new_tables_len == 0) {
     ++		goto exit;
     ++	}
     ++
     ++	for (i = 0; i < add->stack->merged->stack_len; i++) {
     ++		slice_append_string(&table_list,
     ++				    add->stack->merged->stack[i]->name);
     ++		slice_append_string(&table_list, "\n");
     ++	}
     ++	for (i = 0; i < add->new_tables_len; i++) {
     ++		slice_append_string(&table_list, add->new_tables[i]);
     ++		slice_append_string(&table_list, "\n");
     ++	}
     ++
     ++	err = write(add->lock_file_fd, table_list.buf, table_list.len);
     ++	free(slice_yield(&table_list));
     ++	if (err < 0) {
     ++		err = IO_ERROR;
     ++		goto exit;
     ++	}
     ++
     ++	err = close(add->lock_file_fd);
     ++	add->lock_file_fd = 0;
     ++	if (err < 0) {
     ++		err = IO_ERROR;
     ++		goto exit;
     ++	}
     ++
     ++	err = rename(slice_as_string(&add->lock_file_name),
     ++		     add->stack->list_file);
     ++	if (err < 0) {
     ++		err = IO_ERROR;
     ++		goto exit;
     ++	}
     ++
     ++	err = reftable_stack_reload(add->stack);
     ++
     ++exit:
     ++	reftable_addition_close(add);
     ++	return err;
     ++}
     ++
     ++int reftable_stack_new_addition(struct reftable_addition **dest,
     ++				struct reftable_stack *st)
     ++{
     ++	int err = 0;
     ++	*dest = reftable_malloc(sizeof(**dest));
     ++	err = reftable_stack_init_addition(*dest, st);
     ++	if (err) {
     ++		reftable_free(*dest);
     ++		*dest = NULL;
     ++	}
     ++	return err;
     ++}
     ++
     ++int stack_try_add(struct reftable_stack *st,
     ++		  int (*write_table)(struct reftable_writer *wr, void *arg),
     ++		  void *arg)
     ++{
     ++	struct reftable_addition add = { 0 };
     ++	int err = reftable_stack_init_addition(&add, st);
     ++	if (err < 0) {
     ++		goto exit;
     ++	}
     ++
     ++	err = reftable_addition_add(&add, write_table, arg);
     ++	if (err < 0) {
     ++		goto exit;
     ++	}
     ++
     ++	err = reftable_addition_commit(&add);
     ++exit:
     ++	reftable_addition_close(&add);
     ++	return err;
     ++}
     ++
     ++int reftable_addition_add(struct reftable_addition *add,
     ++			  int (*write_table)(struct reftable_writer *wr,
     ++					     void *arg),
     ++			  void *arg)
     ++{
     ++	struct slice temp_tab_file_name = { 0 };
     ++	struct slice tab_file_name = { 0 };
     ++	struct slice next_name = { 0 };
     ++	struct reftable_writer *wr = NULL;
     ++	int err = 0;
     ++	int tab_fd = 0;
     ++	uint64_t next_update_index = 0;
      +
      +	slice_resize(&next_name, 0);
      +	format_name(&next_name, next_update_index, next_update_index);
      +
     -+	slice_set_string(&temp_tab_name, st->reftable_dir);
     -+	slice_append_string(&temp_tab_name, "/");
     -+	slice_append(&temp_tab_name, next_name);
     -+	slice_append_string(&temp_tab_name, ".temp.XXXXXX");
     ++	slice_set_string(&temp_tab_file_name, add->stack->reftable_dir);
     ++	slice_append_string(&temp_tab_file_name, "/");
     ++	slice_append(&temp_tab_file_name, next_name);
     ++	slice_append_string(&temp_tab_file_name, ".temp.XXXXXX");
      +
     -+	tab_fd = mkstemp((char *)slice_as_string(&temp_tab_name));
     ++	tab_fd = mkstemp((char *)slice_as_string(&temp_tab_file_name));
      +	if (tab_fd < 0) {
      +		err = IO_ERROR;
      +		goto exit;
      +	}
      +
     -+	wr = new_writer(fd_writer, &tab_fd, &st->config);
     ++	wr = reftable_new_writer(reftable_fd_write, &tab_fd,
     ++				 &add->stack->config);
      +	err = write_table(wr, arg);
      +	if (err < 0) {
      +		goto exit;
      +	}
      +
     -+	err = writer_close(wr);
     ++	err = reftable_writer_close(wr);
      +	if (err == EMPTY_TABLE_ERROR) {
      +		err = 0;
      +		goto exit;
     @@ -4935,98 +5342,64 @@
      +		goto exit;
      +	}
      +
     -+	{
     -+		int i = 0;
     -+		for (i = 0; i < st->merged->stack_len; i++) {
     -+			slice_append_string(&table_list,
     -+					    st->merged->stack[i]->name);
     -+			slice_append_string(&table_list, "\n");
     -+		}
     -+	}
     -+
      +	format_name(&next_name, wr->min_update_index, wr->max_update_index);
      +	slice_append_string(&next_name, ".ref");
     -+	slice_append(&table_list, next_name);
     -+	slice_append_string(&table_list, "\n");
      +
     -+	slice_set_string(&tab_name, st->reftable_dir);
     -+	slice_append_string(&tab_name, "/");
     -+	slice_append(&tab_name, next_name);
     ++	slice_set_string(&tab_file_name, add->stack->reftable_dir);
     ++	slice_append_string(&tab_file_name, "/");
     ++	slice_append(&tab_file_name, next_name);
      +
     -+	err = rename(slice_as_string(&temp_tab_name),
     -+		     slice_as_string(&tab_name));
     ++	err = rename(slice_as_string(&temp_tab_file_name),
     ++		     slice_as_string(&tab_file_name));
      +	if (err < 0) {
      +		err = IO_ERROR;
      +		goto exit;
      +	}
     -+	free(slice_yield(&temp_tab_name));
      +
     -+	err = write(lock_fd, table_list.buf, table_list.len);
     -+	if (err < 0) {
     -+		err = IO_ERROR;
     -+		goto exit;
     -+	}
     -+	err = close(lock_fd);
     -+	lock_fd = 0;
     -+	if (err < 0) {
     -+		unlink(slice_as_string(&tab_name));
     -+		err = IO_ERROR;
     -+		goto exit;
     -+	}
     -+
     -+	err = rename(slice_as_string(&lock_name), st->list_file);
     -+	if (err < 0) {
     -+		unlink(slice_as_string(&tab_name));
     -+		err = IO_ERROR;
     -+		goto exit;
     -+	}
     -+
     -+	err = stack_reload(st);
     ++	add->new_tables = reftable_realloc(add->new_tables,
     ++					   sizeof(*add->new_tables) *
     ++						   (add->new_tables_len + 1));
     ++	add->new_tables[add->new_tables_len] = slice_to_string(next_name);
     ++	add->new_tables_len++;
      +exit:
      +	if (tab_fd > 0) {
      +		close(tab_fd);
      +		tab_fd = 0;
      +	}
     -+	if (temp_tab_name.len > 0) {
     -+		unlink(slice_as_string(&temp_tab_name));
     -+	}
     -+	unlink(slice_as_string(&lock_name));
     -+
     -+	if (lock_fd > 0) {
     -+		close(lock_fd);
     -+		lock_fd = 0;
     ++	if (temp_tab_file_name.len > 0) {
     ++		unlink(slice_as_string(&temp_tab_file_name));
      +	}
      +
     -+	free(slice_yield(&lock_name));
     -+	free(slice_yield(&temp_tab_name));
     -+	free(slice_yield(&tab_name));
     -+	free(slice_yield(&next_name));
     -+	free(slice_yield(&table_list));
     -+	writer_free(wr);
     ++	reftable_free(slice_yield(&temp_tab_file_name));
     ++	reftable_free(slice_yield(&tab_file_name));
     ++	reftable_free(slice_yield(&next_name));
     ++	reftable_writer_free(wr);
      +	return err;
      +}
      +
     -+uint64_t stack_next_update_index(struct stack *st)
     ++uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
      +{
      +	int sz = st->merged->stack_len;
      +	if (sz > 0) {
     -+		return reader_max_update_index(st->merged->stack[sz - 1]) + 1;
     ++		return reftable_reader_max_update_index(
     ++			       st->merged->stack[sz - 1]) +
     ++		       1;
      +	}
      +	return 1;
      +}
      +
     -+static int stack_compact_locked(struct stack *st, int first, int last,
     ++static int stack_compact_locked(struct reftable_stack *st, int first, int last,
      +				struct slice *temp_tab,
     -+				struct log_expiry_config *config)
     ++				struct reftable_log_expiry_config *config)
      +{
      +	struct slice next_name = { 0 };
      +	int tab_fd = -1;
     -+	struct writer *wr = NULL;
     ++	struct reftable_writer *wr = NULL;
      +	int err = 0;
      +
      +	format_name(&next_name,
     -+		    reader_min_update_index(st->merged->stack[first]),
     -+		    reader_max_update_index(st->merged->stack[first]));
     ++		    reftable_reader_min_update_index(st->merged->stack[first]),
     ++		    reftable_reader_max_update_index(st->merged->stack[first]));
      +
      +	slice_set_string(temp_tab, st->reftable_dir);
      +	slice_append_string(temp_tab, "/");
     @@ -5034,17 +5407,17 @@
      +	slice_append_string(temp_tab, ".temp.XXXXXX");
      +
      +	tab_fd = mkstemp((char *)slice_as_string(temp_tab));
     -+	wr = new_writer(fd_writer, &tab_fd, &st->config);
     ++	wr = reftable_new_writer(reftable_fd_write, &tab_fd, &st->config);
      +
      +	err = stack_write_compact(st, wr, first, last, config);
      +	if (err < 0) {
      +		goto exit;
      +	}
     -+	err = writer_close(wr);
     ++	err = reftable_writer_close(wr);
      +	if (err < 0) {
      +		goto exit;
      +	}
     -+	writer_free(wr);
     ++	reftable_writer_free(wr);
      +
      +	err = close(tab_fd);
      +	tab_fd = 0;
     @@ -5056,46 +5429,49 @@
      +	}
      +	if (err != 0 && temp_tab->len > 0) {
      +		unlink(slice_as_string(temp_tab));
     -+		free(slice_yield(temp_tab));
     ++		reftable_free(slice_yield(temp_tab));
      +	}
     -+	free(slice_yield(&next_name));
     ++	reftable_free(slice_yield(&next_name));
      +	return err;
      +}
      +
     -+int stack_write_compact(struct stack *st, struct writer *wr, int first,
     -+			int last, struct log_expiry_config *config)
     ++int stack_write_compact(struct reftable_stack *st, struct reftable_writer *wr,
     ++			int first, int last,
     ++			struct reftable_log_expiry_config *config)
      +{
      +	int subtabs_len = last - first + 1;
     -+	struct reader **subtabs =
     -+		calloc(sizeof(struct reader *), last - first + 1);
     -+	struct merged_table *mt = NULL;
     ++	struct reftable_reader **subtabs = reftable_calloc(
     ++		sizeof(struct reftable_reader *) * (last - first + 1));
     ++	struct reftable_merged_table *mt = NULL;
      +	int err = 0;
     -+	struct iterator it = { 0 };
     -+	struct ref_record ref = { 0 };
     -+	struct log_record log = { 0 };
     ++	struct reftable_iterator it = { 0 };
     ++	struct reftable_ref_record ref = { 0 };
     ++	struct reftable_log_record log = { 0 };
      +
      +	int i = 0, j = 0;
      +	for (i = first, j = 0; i <= last; i++) {
     -+		struct reader *t = st->merged->stack[i];
     ++		struct reftable_reader *t = st->merged->stack[i];
      +		subtabs[j++] = t;
      +		st->stats.bytes += t->size;
      +	}
     -+	writer_set_limits(wr, st->merged->stack[first]->min_update_index,
     -+			  st->merged->stack[last]->max_update_index);
     ++	reftable_writer_set_limits(wr,
     ++				   st->merged->stack[first]->min_update_index,
     ++				   st->merged->stack[last]->max_update_index);
      +
     -+	err = new_merged_table(&mt, subtabs, subtabs_len, st->config.hash_id);
     ++	err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
     ++					st->config.hash_id);
      +	if (err < 0) {
     -+		free(subtabs);
     ++		reftable_free(subtabs);
      +		goto exit;
      +	}
      +
     -+	err = merged_table_seek_ref(mt, &it, "");
     ++	err = reftable_merged_table_seek_ref(mt, &it, "");
      +	if (err < 0) {
      +		goto exit;
      +	}
      +
      +	while (true) {
     -+		err = iterator_next_ref(it, &ref);
     ++		err = reftable_iterator_next_ref(it, &ref);
      +		if (err > 0) {
      +			err = 0;
      +			break;
     @@ -5103,23 +5479,23 @@
      +		if (err < 0) {
      +			break;
      +		}
     -+		if (first == 0 && ref_record_is_deletion(&ref)) {
     ++		if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
      +			continue;
      +		}
      +
     -+		err = writer_add_ref(wr, &ref);
     ++		err = reftable_writer_add_ref(wr, &ref);
      +		if (err < 0) {
      +			break;
      +		}
      +	}
      +
     -+	err = merged_table_seek_log(mt, &it, "");
     ++	err = reftable_merged_table_seek_log(mt, &it, "");
      +	if (err < 0) {
      +		goto exit;
      +	}
      +
      +	while (true) {
     -+		err = iterator_next_log(it, &log);
     ++		err = reftable_iterator_next_log(it, &log);
      +		if (err > 0) {
      +			err = 0;
      +			break;
     @@ -5127,7 +5503,7 @@
      +		if (err < 0) {
      +			break;
      +		}
     -+		if (first == 0 && log_record_is_deletion(&log)) {
     ++		if (first == 0 && reftable_log_record_is_deletion(&log)) {
      +			continue;
      +		}
      +
     @@ -5143,28 +5519,28 @@
      +			continue;
      +		}
      +
     -+		err = writer_add_log(wr, &log);
     ++		err = reftable_writer_add_log(wr, &log);
      +		if (err < 0) {
      +			break;
      +		}
      +	}
      +
      +exit:
     -+	iterator_destroy(&it);
     ++	reftable_iterator_destroy(&it);
      +	if (mt != NULL) {
      +		merged_table_clear(mt);
     -+		merged_table_free(mt);
     ++		reftable_merged_table_free(mt);
      +	}
     -+	ref_record_clear(&ref);
     ++	reftable_ref_record_clear(&ref);
      +
      +	return err;
      +}
      +
      +/* <  0: error. 0 == OK, > 0 attempt failed; could retry. */
     -+static int stack_compact_range(struct stack *st, int first, int last,
     -+			       struct log_expiry_config *expiry)
     ++static int stack_compact_range(struct reftable_stack *st, int first, int last,
     ++			       struct reftable_log_expiry_config *expiry)
      +{
     -+	struct slice temp_tab_name = { 0 };
     ++	struct slice temp_tab_file_name = { 0 };
      +	struct slice new_table_name = { 0 };
      +	struct slice lock_file_name = { 0 };
      +	struct slice ref_list_contents = { 0 };
     @@ -5173,8 +5549,10 @@
      +	bool have_lock = false;
      +	int lock_file_fd = 0;
      +	int compact_count = last - first + 1;
     -+	char **delete_on_success = calloc(sizeof(char *), compact_count + 1);
     -+	char **subtable_locks = calloc(sizeof(char *), compact_count + 1);
     ++	char **delete_on_success =
     ++		reftable_calloc(sizeof(char *) * (compact_count + 1));
     ++	char **subtable_locks =
     ++		reftable_calloc(sizeof(char *) * (compact_count + 1));
      +	int i = 0;
      +	int j = 0;
      +	bool is_empty_table = false;
     @@ -5206,14 +5584,14 @@
      +	}
      +
      +	for (i = first, j = 0; i <= last; i++) {
     -+		struct slice subtab_name = { 0 };
     ++		struct slice subtab_file_name = { 0 };
      +		struct slice subtab_lock = { 0 };
     -+		slice_set_string(&subtab_name, st->reftable_dir);
     -+		slice_append_string(&subtab_name, "/");
     -+		slice_append_string(&subtab_name,
     ++		slice_set_string(&subtab_file_name, st->reftable_dir);
     ++		slice_append_string(&subtab_file_name, "/");
     ++		slice_append_string(&subtab_file_name,
      +				    reader_name(st->merged->stack[i]));
      +
     -+		slice_copy(&subtab_lock, subtab_name);
     ++		slice_copy(&subtab_lock, subtab_file_name);
      +		slice_append_string(&subtab_lock, ".lock");
      +
      +		{
     @@ -5231,7 +5609,8 @@
      +		}
      +
      +		subtable_locks[j] = (char *)slice_as_string(&subtab_lock);
     -+		delete_on_success[j] = (char *)slice_as_string(&subtab_name);
     ++		delete_on_success[j] =
     ++			(char *)slice_as_string(&subtab_file_name);
      +		j++;
      +
      +		if (err != 0) {
     @@ -5245,7 +5624,8 @@
      +	}
      +	have_lock = false;
      +
     -+	err = stack_compact_locked(st, first, last, &temp_tab_name, expiry);
     ++	err = stack_compact_locked(st, first, last, &temp_tab_file_name,
     ++				   expiry);
      +	/* Compaction + tombstones can create an empty table out of non-empty
      +	 * tables. */
      +	is_empty_table = (err == EMPTY_TABLE_ERROR);
     @@ -5278,7 +5658,7 @@
      +	slice_append(&new_table_path, new_table_name);
      +
      +	if (!is_empty_table) {
     -+		err = rename(slice_as_string(&temp_tab_name),
     ++		err = rename(slice_as_string(&temp_tab_file_name),
      +			     slice_as_string(&new_table_path));
      +		if (err < 0) {
      +			goto exit;
     @@ -5329,7 +5709,7 @@
      +		}
      +	}
      +
     -+	err = stack_reload_maybe_reuse(st, first < last);
     ++	err = reftable_stack_reload_maybe_reuse(st, first < last);
      +exit:
      +	free_names(delete_on_success);
      +	{
     @@ -5347,21 +5727,23 @@
      +	if (have_lock) {
      +		unlink(slice_as_string(&lock_file_name));
      +	}
     -+	free(slice_yield(&new_table_name));
     -+	free(slice_yield(&new_table_path));
     -+	free(slice_yield(&ref_list_contents));
     -+	free(slice_yield(&temp_tab_name));
     -+	free(slice_yield(&lock_file_name));
     ++	reftable_free(slice_yield(&new_table_name));
     ++	reftable_free(slice_yield(&new_table_path));
     ++	reftable_free(slice_yield(&ref_list_contents));
     ++	reftable_free(slice_yield(&temp_tab_file_name));
     ++	reftable_free(slice_yield(&lock_file_name));
      +	return err;
      +}
      +
     -+int stack_compact_all(struct stack *st, struct log_expiry_config *config)
     ++int reftable_stack_compact_all(struct reftable_stack *st,
     ++			       struct reftable_log_expiry_config *config)
      +{
      +	return stack_compact_range(st, 0, st->merged->stack_len - 1, config);
      +}
      +
     -+static int stack_compact_range_stats(struct stack *st, int first, int last,
     -+				     struct log_expiry_config *config)
     ++static int stack_compact_range_stats(struct reftable_stack *st, int first,
     ++				     int last,
     ++				     struct reftable_log_expiry_config *config)
      +{
      +	int err = stack_compact_range(st, first, last, config);
      +	if (err > 0) {
     @@ -5387,7 +5769,7 @@
      +
      +struct segment *sizes_to_segments(int *seglen, uint64_t *sizes, int n)
      +{
     -+	struct segment *segs = calloc(sizeof(struct segment), n);
     ++	struct segment *segs = reftable_calloc(sizeof(struct segment) * n);
      +	int next = 0;
      +	struct segment cur = { 0 };
      +	int i = 0;
     @@ -5406,8 +5788,9 @@
      +		cur.end = i + 1;
      +		cur.bytes += sizes[i];
      +	}
     -+
     -+	segs[next++] = cur;
     ++	if (next > 0) {
     ++		segs[next++] = cur;
     ++	}
      +	*seglen = next;
      +	return segs;
      +}
     @@ -5440,13 +5823,14 @@
      +		min_seg.bytes += sizes[prev];
      +	}
      +
     -+	free(segs);
     ++	reftable_free(segs);
      +	return min_seg;
      +}
      +
     -+static uint64_t *stack_table_sizes_for_compaction(struct stack *st)
     ++static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
      +{
     -+	uint64_t *sizes = calloc(sizeof(uint64_t), st->merged->stack_len);
     ++	uint64_t *sizes =
     ++		reftable_calloc(sizeof(uint64_t) * st->merged->stack_len);
      +	int i = 0;
      +	for (i = 0; i < st->merged->stack_len; i++) {
      +		/* overhead is 24 + 68 = 92. */
     @@ -5455,12 +5839,12 @@
      +	return sizes;
      +}
      +
     -+int stack_auto_compact(struct stack *st)
     ++int reftable_stack_auto_compact(struct reftable_stack *st)
      +{
      +	uint64_t *sizes = stack_table_sizes_for_compaction(st);
      +	struct segment seg =
      +		suggest_compaction_segment(sizes, st->merged->stack_len);
     -+	free(sizes);
     ++	reftable_free(sizes);
      +	if (segment_size(&seg) > 0) {
      +		return stack_compact_range_stats(st, seg.start, seg.end - 1,
      +						 NULL);
     @@ -5469,58 +5853,61 @@
      +	return 0;
      +}
      +
     -+struct compaction_stats *stack_compaction_stats(struct stack *st)
     ++struct reftable_compaction_stats *
     ++reftable_stack_compaction_stats(struct reftable_stack *st)
      +{
      +	return &st->stats;
      +}
      +
     -+int stack_read_ref(struct stack *st, const char *refname,
     -+		   struct ref_record *ref)
     ++int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
     ++			    struct reftable_ref_record *ref)
      +{
     -+	struct iterator it = { 0 };
     -+	struct merged_table *mt = stack_merged_table(st);
     -+	int err = merged_table_seek_ref(mt, &it, refname);
     ++	struct reftable_iterator it = { 0 };
     ++	struct reftable_merged_table *mt = reftable_stack_merged_table(st);
     ++	int err = reftable_merged_table_seek_ref(mt, &it, refname);
      +	if (err) {
      +		goto exit;
      +	}
      +
     -+	err = iterator_next_ref(it, ref);
     ++	err = reftable_iterator_next_ref(it, ref);
      +	if (err) {
      +		goto exit;
      +	}
      +
     -+	if (strcmp(ref->ref_name, refname) || ref_record_is_deletion(ref)) {
     ++	if (strcmp(ref->ref_name, refname) ||
     ++	    reftable_ref_record_is_deletion(ref)) {
      +		err = 1;
      +		goto exit;
      +	}
      +
      +exit:
     -+	iterator_destroy(&it);
     ++	reftable_iterator_destroy(&it);
      +	return err;
      +}
      +
     -+int stack_read_log(struct stack *st, const char *refname,
     -+		   struct log_record *log)
     ++int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
     ++			    struct reftable_log_record *log)
      +{
     -+	struct iterator it = { 0 };
     -+	struct merged_table *mt = stack_merged_table(st);
     -+	int err = merged_table_seek_log(mt, &it, refname);
     ++	struct reftable_iterator it = { 0 };
     ++	struct reftable_merged_table *mt = reftable_stack_merged_table(st);
     ++	int err = reftable_merged_table_seek_log(mt, &it, refname);
      +	if (err) {
      +		goto exit;
      +	}
      +
     -+	err = iterator_next_log(it, log);
     ++	err = reftable_iterator_next_log(it, log);
      +	if (err) {
      +		goto exit;
      +	}
      +
     -+	if (strcmp(log->ref_name, refname) || log_record_is_deletion(log)) {
     ++	if (strcmp(log->ref_name, refname) ||
     ++	    reftable_log_record_is_deletion(log)) {
      +		err = 1;
      +		goto exit;
      +	}
      +
      +exit:
     -+	iterator_destroy(&it);
     ++	reftable_iterator_destroy(&it);
      +	return err;
      +}
      
     @@ -5542,21 +5929,23 @@
      +
      +#include "reftable.h"
      +
     -+struct stack {
     ++struct reftable_stack {
      +	char *list_file;
      +	char *reftable_dir;
      +
     -+	struct write_options config;
     ++	struct reftable_write_options config;
      +
     -+	struct merged_table *merged;
     -+	struct compaction_stats stats;
     ++	struct reftable_merged_table *merged;
     ++	struct reftable_compaction_stats stats;
      +};
      +
      +int read_lines(const char *filename, char ***lines);
     -+int stack_try_add(struct stack *st,
     -+		  int (*write_table)(struct writer *wr, void *arg), void *arg);
     -+int stack_write_compact(struct stack *st, struct writer *wr, int first,
     -+			int last, struct log_expiry_config *config);
     ++int stack_try_add(struct reftable_stack *st,
     ++		  int (*write_table)(struct reftable_writer *wr, void *arg),
     ++		  void *arg);
     ++int stack_write_compact(struct reftable_stack *st, struct reftable_writer *wr,
     ++			int first, int last,
     ++			struct reftable_log_expiry_config *config);
      +int fastlog2(uint64_t sz);
      +
      +struct segment {
     @@ -5644,6 +6033,7 @@
      +
      +#include "tree.h"
      +
     ++#include "basics.h"
      +#include "system.h"
      +
      +struct tree_node *tree_search(void *key, struct tree_node **rootp,
     @@ -5655,7 +6045,7 @@
      +			return NULL;
      +		} else {
      +			struct tree_node *n =
     -+				calloc(sizeof(struct tree_node), 1);
     ++				reftable_calloc(sizeof(struct tree_node));
      +			n->key = key;
      +			*rootp = n;
      +			return *rootp;
     @@ -5698,7 +6088,7 @@
      +	if (t->right != NULL) {
      +		tree_free(t->right);
      +	}
     -+	free(t);
     ++	reftable_free(t);
      +}
      
       diff --git a/reftable/tree.h b/reftable/tree.h
     @@ -5743,6 +6133,7 @@
      +((cd reftable-repo && git fetch origin && git checkout origin/master ) ||
      +git clone https://github.com/google/reftable reftable-repo) && \
      +cp reftable-repo/c/*.[ch] reftable/ && \
     ++cp reftable-repo/c/include/*.[ch] reftable/ && \
      +cp reftable-repo/LICENSE reftable/ &&
      +git --git-dir reftable-repo/.git show --no-patch origin/master \
      +> reftable/VERSION && \
     @@ -5773,7 +6164,8 @@
      +#include "reftable.h"
      +#include "tree.h"
      +
     -+static struct block_stats *writer_block_stats(struct writer *w, byte typ)
     ++static struct reftable_block_stats *
     ++writer_reftable_block_stats(struct reftable_writer *w, byte typ)
      +{
      +	switch (typ) {
      +	case 'r':
     @@ -5791,18 +6183,19 @@
      +
      +/* write data, queuing the padding for the next write. Returns negative for
      + * error. */
     -+static int padded_write(struct writer *w, byte *data, size_t len, int padding)
     ++static int padded_write(struct reftable_writer *w, byte *data, size_t len,
     ++			int padding)
      +{
      +	int n = 0;
      +	if (w->pending_padding > 0) {
     -+		byte *zeroed = calloc(w->pending_padding, 1);
     ++		byte *zeroed = reftable_calloc(w->pending_padding);
      +		int n = w->write(w->write_arg, zeroed, w->pending_padding);
      +		if (n < 0) {
      +			return n;
      +		}
      +
      +		w->pending_padding = 0;
     -+		free(zeroed);
     ++		reftable_free(zeroed);
      +	}
      +
      +	w->pending_padding = padding;
     @@ -5814,7 +6207,7 @@
      +	return 0;
      +}
      +
     -+static void options_set_defaults(struct write_options *opts)
     ++static void options_set_defaults(struct reftable_write_options *opts)
      +{
      +	if (opts->restart_interval == 0) {
      +		opts->restart_interval = 16;
     @@ -5828,25 +6221,31 @@
      +	}
      +}
      +
     -+static int writer_write_header(struct writer *w, byte *dest)
     ++static int writer_version(struct reftable_writer *w)
     ++{
     ++	return (w->opts.hash_id == 0 || w->opts.hash_id == SHA1_ID) ? 1 : 2;
     ++}
     ++
     ++static int writer_write_header(struct reftable_writer *w, byte *dest)
      +{
      +	memcpy((char *)dest, "REFT", 4);
      +
     -+	/* DO NOT SUBMIT.  This has not been encoded in the standard yet. */
     -+	dest[4] = (hash_size(w->opts.hash_id) == SHA1_SIZE) ? 1 : 2; /* version
     -+								      */
     ++	dest[4] = writer_version(w);
      +
      +	put_be24(dest + 5, w->opts.block_size);
      +	put_be64(dest + 8, w->min_update_index);
      +	put_be64(dest + 16, w->max_update_index);
     -+	return 24;
     ++	if (writer_version(w) == 2) {
     ++		put_be32(dest + 24, w->opts.hash_id);
     ++	}
     ++	return header_size(writer_version(w));
      +}
      +
     -+static void writer_reinit_block_writer(struct writer *w, byte typ)
     ++static void writer_reinit_block_writer(struct reftable_writer *w, byte typ)
      +{
      +	int block_start = 0;
      +	if (w->next == 0) {
     -+		block_start = HEADER_SIZE;
     ++		block_start = header_size(writer_version(w));
      +	}
      +
      +	block_writer_init(&w->block_writer_data, typ, w->block,
     @@ -5856,16 +6255,18 @@
      +	w->block_writer->restart_interval = w->opts.restart_interval;
      +}
      +
     -+struct writer *new_writer(int (*writer_func)(void *, byte *, int),
     -+			  void *writer_arg, struct write_options *opts)
     ++struct reftable_writer *
     ++reftable_new_writer(int (*writer_func)(void *, byte *, int), void *writer_arg,
     ++		    struct reftable_write_options *opts)
      +{
     -+	struct writer *wp = calloc(sizeof(struct writer), 1);
     ++	struct reftable_writer *wp =
     ++		reftable_calloc(sizeof(struct reftable_writer));
      +	options_set_defaults(opts);
      +	if (opts->block_size >= (1 << 24)) {
      +		/* TODO - error return? */
      +		abort();
      +	}
     -+	wp->block = calloc(opts->block_size, 1);
     ++	wp->block = reftable_calloc(opts->block_size);
      +	wp->write = writer_func;
      +	wp->write_arg = writer_arg;
      +	wp->opts = *opts;
     @@ -5874,16 +6275,17 @@
      +	return wp;
      +}
      +
     -+void writer_set_limits(struct writer *w, uint64_t min, uint64_t max)
     ++void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
     ++				uint64_t max)
      +{
      +	w->min_update_index = min;
      +	w->max_update_index = max;
      +}
      +
     -+void writer_free(struct writer *w)
     ++void reftable_writer_free(struct reftable_writer *w)
      +{
     -+	free(w->block);
     -+	free(w);
     ++	reftable_free(w->block);
     ++	reftable_free(w);
      +}
      +
      +struct obj_index_tree_node {
     @@ -5899,7 +6301,7 @@
      +			     ((const struct obj_index_tree_node *)b)->hash);
      +}
      +
     -+static void writer_index_hash(struct writer *w, struct slice hash)
     ++static void writer_index_hash(struct reftable_writer *w, struct slice hash)
      +{
      +	uint64_t off = w->next;
      +
     @@ -5909,7 +6311,7 @@
      +					     &obj_index_tree_node_compare, 0);
      +	struct obj_index_tree_node *key = NULL;
      +	if (node == NULL) {
     -+		key = calloc(sizeof(struct obj_index_tree_node), 1);
     ++		key = reftable_calloc(sizeof(struct obj_index_tree_node));
      +		slice_copy(&key->hash, hash);
      +		tree_search((void *)key, &w->obj_index_tree,
      +			    &obj_index_tree_node_compare, 1);
     @@ -5923,14 +6325,14 @@
      +
      +	if (key->offset_len == key->offset_cap) {
      +		key->offset_cap = 2 * key->offset_cap + 1;
     -+		key->offsets = realloc(key->offsets,
     -+				       sizeof(uint64_t) * key->offset_cap);
     ++		key->offsets = reftable_realloc(
     ++			key->offsets, sizeof(uint64_t) * key->offset_cap);
      +	}
      +
      +	key->offsets[key->offset_len++] = off;
      +}
      +
     -+static int writer_add_record(struct writer *w, struct record rec)
     ++static int writer_add_record(struct reftable_writer *w, struct record rec)
      +{
      +	int result = -1;
      +	struct slice key = { 0 };
     @@ -5967,14 +6369,15 @@
      +
      +	result = 0;
      +exit:
     -+	free(slice_yield(&key));
     ++	reftable_free(slice_yield(&key));
      +	return result;
      +}
      +
     -+int writer_add_ref(struct writer *w, struct ref_record *ref)
     ++int reftable_writer_add_ref(struct reftable_writer *w,
     ++			    struct reftable_ref_record *ref)
      +{
      +	struct record rec = { 0 };
     -+	struct ref_record copy = *ref;
     ++	struct reftable_ref_record copy = *ref;
      +	int err = 0;
      +
      +	if (ref->ref_name == NULL) {
     @@ -6010,18 +6413,20 @@
      +	return 0;
      +}
      +
     -+int writer_add_refs(struct writer *w, struct ref_record *refs, int n)
     ++int reftable_writer_add_refs(struct reftable_writer *w,
     ++			     struct reftable_ref_record *refs, int n)
      +{
      +	int err = 0;
      +	int i = 0;
     -+	QSORT(refs, n, ref_record_compare_name);
     ++	QSORT(refs, n, reftable_ref_record_compare_name);
      +	for (i = 0; err == 0 && i < n; i++) {
     -+		err = writer_add_ref(w, &refs[i]);
     ++		err = reftable_writer_add_ref(w, &refs[i]);
      +	}
      +	return err;
      +}
      +
     -+int writer_add_log(struct writer *w, struct log_record *log)
     ++int reftable_writer_add_log(struct reftable_writer *w,
     ++			    struct reftable_log_record *log)
      +{
      +	if (log->ref_name == NULL) {
      +		return API_ERROR;
     @@ -6047,18 +6452,19 @@
      +	}
      +}
      +
     -+int writer_add_logs(struct writer *w, struct log_record *logs, int n)
     ++int reftable_writer_add_logs(struct reftable_writer *w,
     ++			     struct reftable_log_record *logs, int n)
      +{
      +	int err = 0;
      +	int i = 0;
     -+	QSORT(logs, n, log_record_compare_key);
     ++	QSORT(logs, n, reftable_log_record_compare_key);
      +	for (i = 0; err == 0 && i < n; i++) {
     -+		err = writer_add_log(w, &logs[i]);
     ++		err = reftable_writer_add_log(w, &logs[i]);
      +	}
      +	return err;
      +}
      +
     -+static int writer_finish_section(struct writer *w)
     ++static int writer_finish_section(struct reftable_writer *w)
      +{
      +	byte typ = block_writer_type(w->block_writer);
      +	uint64_t index_start = 0;
     @@ -6105,9 +6511,9 @@
      +			assert(err == 0);
      +		}
      +		for (i = 0; i < idx_len; i++) {
     -+			free(slice_yield(&idx[i].last_key));
     ++			reftable_free(slice_yield(&idx[i].last_key));
      +		}
     -+		free(idx);
     ++		reftable_free(idx);
      +	}
      +
      +	writer_clear_index(w);
     @@ -6118,7 +6524,8 @@
      +	}
      +
      +	{
     -+		struct block_stats *bstats = writer_block_stats(w, typ);
     ++		struct reftable_block_stats *bstats =
     ++			writer_reftable_block_stats(w, typ);
      +		bstats->index_blocks =
      +			w->stats.idx_stats.blocks - before_blocks;
      +		bstats->index_offset = index_start;
     @@ -6150,7 +6557,7 @@
      +}
      +
      +struct write_record_arg {
     -+	struct writer *w;
     ++	struct reftable_writer *w;
      +	int err;
      +};
      +
     @@ -6199,11 +6606,11 @@
      +	struct obj_index_tree_node *entry = (struct obj_index_tree_node *)key;
      +
      +	FREE_AND_NULL(entry->offsets);
     -+	free(slice_yield(&entry->hash));
     -+	free(entry);
     ++	reftable_free(slice_yield(&entry->hash));
     ++	reftable_free(entry);
      +}
      +
     -+static int writer_dump_object_index(struct writer *w)
     ++static int writer_dump_object_index(struct reftable_writer *w)
      +{
      +	struct write_record_arg closure = { .w = w };
      +	struct common_prefix_arg common = { 0 };
     @@ -6224,7 +6631,7 @@
      +	return writer_finish_section(w);
      +}
      +
     -+int writer_finish_public_section(struct writer *w)
     ++int writer_finish_public_section(struct reftable_writer *w)
      +{
      +	byte typ = 0;
      +	int err = 0;
     @@ -6256,9 +6663,9 @@
      +	return 0;
      +}
      +
     -+int writer_close(struct writer *w)
     ++int reftable_writer_close(struct reftable_writer *w)
      +{
     -+	byte footer[68];
     ++	byte footer[72];
      +	byte *p = footer;
      +
      +	int err = writer_finish_public_section(w);
     @@ -6266,8 +6673,7 @@
      +		goto exit;
      +	}
      +
     -+	writer_write_header(w, footer);
     -+	p += 24;
     ++	p += writer_write_header(w, footer);
      +	put_be64(p, w->stats.ref_stats.index_offset);
      +	p += 8;
      +	put_be64(p, (w->stats.obj_stats.offset) << 5 | w->stats.object_id_len);
     @@ -6284,7 +6690,7 @@
      +	p += 4;
      +	w->pending_padding = 0;
      +
     -+	err = padded_write(w, footer, sizeof(footer), 0);
     ++	err = padded_write(w, footer, footer_size(writer_version(w)), 0);
      +	if (err < 0) {
      +		goto exit;
      +	}
     @@ -6298,15 +6704,15 @@
      +	/* free up memory. */
      +	block_writer_clear(&w->block_writer_data);
      +	writer_clear_index(w);
     -+	free(slice_yield(&w->last_key));
     ++	reftable_free(slice_yield(&w->last_key));
      +	return err;
      +}
      +
     -+void writer_clear_index(struct writer *w)
     ++void writer_clear_index(struct reftable_writer *w)
      +{
      +	int i = 0;
      +	for (i = 0; i < w->index_len; i++) {
     -+		free(slice_yield(&w->index[i].last_key));
     ++		reftable_free(slice_yield(&w->index[i].last_key));
      +	}
      +
      +	FREE_AND_NULL(w->index);
     @@ -6316,10 +6722,11 @@
      +
      +const int debug = 0;
      +
     -+static int writer_flush_nonempty_block(struct writer *w)
     ++static int writer_flush_nonempty_block(struct reftable_writer *w)
      +{
      +	byte typ = block_writer_type(w->block_writer);
     -+	struct block_stats *bstats = writer_block_stats(w, typ);
     ++	struct reftable_block_stats *bstats =
     ++		writer_reftable_block_stats(w, typ);
      +	uint64_t block_typ_off = (bstats->blocks == 0) ? w->next : 0;
      +	int raw_bytes = block_writer_finish(w->block_writer);
      +	int padding = 0;
     @@ -6358,8 +6765,8 @@
      +
      +	if (w->index_cap == w->index_len) {
      +		w->index_cap = 2 * w->index_cap + 1;
     -+		w->index = realloc(w->index,
     -+				   sizeof(struct index_record) * w->index_cap);
     ++		w->index = reftable_realloc(
     ++			w->index, sizeof(struct index_record) * w->index_cap);
      +	}
      +
      +	{
     @@ -6377,7 +6784,7 @@
      +	return 0;
      +}
      +
     -+int writer_flush_block(struct writer *w)
     ++int writer_flush_block(struct reftable_writer *w)
      +{
      +	if (w->block_writer == NULL) {
      +		return 0;
     @@ -6388,7 +6795,7 @@
      +	return writer_flush_nonempty_block(w);
      +}
      +
     -+struct stats *writer_stats(struct writer *w)
     ++const struct reftable_stats *writer_stats(struct reftable_writer *w)
      +{
      +	return &w->stats;
      +}
     @@ -6415,7 +6822,7 @@
      +#include "slice.h"
      +#include "tree.h"
      +
     -+struct writer {
     ++struct reftable_writer {
      +	int (*write)(void *, byte *, int);
      +	void *write_arg;
      +	int pending_padding;
     @@ -6423,11 +6830,11 @@
      +
      +	uint64_t next;
      +	uint64_t min_update_index, max_update_index;
     -+	struct write_options opts;
     ++	struct reftable_write_options opts;
      +
      +	byte *block;
     -+	struct block_writer *block_writer;
     -+	struct block_writer block_writer_data;
     ++	struct reftable_block_writer *block_writer;
     ++	struct reftable_block_writer block_writer_data;
      +	struct index_record *index;
      +	int index_len;
      +	int index_cap;
     @@ -6435,12 +6842,12 @@
      +	/* tree for use with tsearch */
      +	struct tree_node *obj_index_tree;
      +
     -+	struct stats stats;
     ++	struct reftable_stats stats;
      +};
      +
     -+int writer_flush_block(struct writer *w);
     -+void writer_clear_index(struct writer *w);
     -+int writer_finish_public_section(struct writer *w);
     ++int writer_flush_block(struct reftable_writer *w);
     ++void writer_clear_index(struct reftable_writer *w);
     ++int writer_finish_public_section(struct reftable_writer *w);
      +
      +#endif
      
  6:  a622d8066c7 !  9:  b29c4ecc1c4 Reftable support for git-core
     @@ -6,6 +6,7 @@
      
          TODO:
      
     +     * "git show-ref" shows "HEAD"
           * Resolve spots marked with XXX
           * Test strategy?
      
     @@ -104,8 +105,9 @@ $^
       		}
       	}
       
     --	init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
     +-	init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
      +	init_db(git_dir, real_git_dir, option_template,
     ++                GIT_HASH_UNKNOWN,
      +		DEFAULT_REF_STORAGE, /* XXX */
      +		INIT_DB_QUIET);
       
     @@ -116,20 +118,28 @@ $^
       --- a/builtin/init-db.c
       +++ b/builtin/init-db.c
      @@
     + 	return 1;
       }
       
     - static int create_default_files(const char *template_path,
     --				const char *original_git_dir)
     -+				const char *original_git_dir,
     -+				const char *ref_storage_format, int flags)
     +-void initialize_repository_version(int hash_algo)
     ++void initialize_repository_version(int hash_algo, const char *ref_storage_format)
       {
     - 	struct stat st1;
     - 	struct strbuf buf = STRBUF_INIT;
     + 	char repo_version_string[10];
     + 	int repo_version = GIT_REPO_VERSION;
     +@@
     + 		die(_("The hash algorithm %s is not supported in this build."), hash_algos[hash_algo].name);
     + #endif
     + 
     +-	if (hash_algo != GIT_HASH_SHA1)
     ++	if (hash_algo != GIT_HASH_SHA1 || !strcmp(ref_storage_format, "reftable"))
     + 		repo_version = GIT_REPO_VERSION_READ;
     + 
     + 	/* This forces creation of new config file */
      @@
       	is_bare_repository_cfg = init_is_bare_repository;
       	if (init_shared_repository != -1)
       		set_shared_repository(init_shared_repository);
     -+	the_repository->ref_storage_format = xstrdup(ref_storage_format);
     ++	the_repository->ref_storage_format = xstrdup(fmt->ref_storage);
       
       	/*
       	 * We would have created the above under user's umask -- under
     @@ -166,35 +176,28 @@ $^
      +		 */
       	}
       
     - 	/* This forces creation of new config file */
     --	xsnprintf(repo_version_string, sizeof(repo_version_string),
     --		  "%d", GIT_REPO_VERSION);
     -+	xsnprintf(repo_version_string, sizeof(repo_version_string), "%d",
     -+		  !strcmp(ref_storage_format, "reftable") ?
     -+			  GIT_REPO_VERSION_READ :
     -+			  GIT_REPO_VERSION);
     - 	git_config_set("core.repositoryformatversion", repo_version_string);
     +-	initialize_repository_version(fmt->hash_algo);
     ++	initialize_repository_version(fmt->hash_algo, fmt->ref_storage);
       
       	/* Check filemode trustability */
     + 	path = git_path_buf(&buf, "config");
      @@
       }
       
       int init_db(const char *git_dir, const char *real_git_dir,
     --	    const char *template_dir, unsigned int flags)
     -+	    const char *template_dir, const char *ref_storage_format,
     -+	    unsigned int flags)
     +-	    const char *template_dir, int hash, unsigned int flags)
     ++	    const char *template_dir, int hash, const char *ref_storage_format,
     ++            unsigned int flags)
       {
       	int reinit;
       	int exist_ok = flags & INIT_DB_EXIST_OK;
      @@
     + 	 * is an attempt to reinitialize new repository with an old tool.
       	 */
     - 	check_repository_format();
     - 
     --	reinit = create_default_files(template_dir, original_git_dir);
     -+	reinit = create_default_files(template_dir, original_git_dir,
     -+				      ref_storage_format, flags);
     + 	check_repository_format(&repo_fmt);
     ++        repo_fmt.ref_storage = xstrdup(ref_storage_format);
       
     - 	create_object_directory();
     + 	validate_hash_algorithm(&repo_fmt, hash);
       
      @@
       		git_config_set("receive.denyNonFastforwards", "true");
     @@ -213,7 +216,9 @@ $^
       	const char *real_git_dir = NULL;
       	const char *work_tree;
       	const char *template_dir = NULL;
     - 	unsigned int flags = 0;
     +@@
     + 	const char *object_format = NULL;
     + 	int hash_algo = GIT_HASH_UNKNOWN;
       	const struct option init_db_options[] = {
      -		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
      -				N_("directory from which templates will be used")),
     @@ -235,7 +240,7 @@ $^
      +			   N_("the ref storage format to use")),
       		OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
       			   N_("separate git dir from working tree")),
     - 		OPT_END()
     + 		OPT_STRING(0, "object-format", &object_format, N_("hash"),
      @@
       	}
       
     @@ -245,21 +250,21 @@ $^
       	UNLEAK(work_tree);
       
       	flags |= INIT_DB_EXIST_OK;
     --	return init_db(git_dir, real_git_dir, template_dir, flags);
     -+	return init_db(git_dir, real_git_dir, template_dir, ref_storage_format,
     -+		       flags);
     +-	return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
     ++	return init_db(git_dir, real_git_dir, template_dir, hash_algo, ref_storage_format, flags);
       }
      
       diff --git a/cache.h b/cache.h
       --- a/cache.h
       +++ b/cache.h
      @@
     - #define INIT_DB_EXIST_OK 0x0002
       
       int init_db(const char *git_dir, const char *real_git_dir,
     --	    const char *template_dir, unsigned int flags);
     -+	    const char *template_dir, const char *ref_storage_format,
     -+	    unsigned int flags);
     + 	    const char *template_dir, int hash_algo,
     ++            const char *ref_storage_format,
     + 	    unsigned int flags);
     +-void initialize_repository_version(int hash_algo);
     ++void initialize_repository_version(int hash_algo, const char *ref_storage_format);
       
       void sanitize_stdfds(void);
       int daemonize(void);
     @@ -350,7 +355,6 @@ $^
       struct string_list_item;
       struct worktree;
       
     -+/* XXX where should this be? */
      +#define DEFAULT_REF_STORAGE "files"
      +
       /*
     @@ -386,26 +390,25 @@ $^
      +
      +extern struct ref_storage_be refs_be_reftable;
      +
     -+struct reftable_ref_store {
     ++struct git_reftable_ref_store {
      +	struct ref_store base;
      +	unsigned int store_flags;
      +
      +	int err;
      +	char *reftable_dir;
     -+	char *table_list_file;
     -+	struct stack *stack;
     ++	struct reftable_stack *stack;
      +};
      +
     -+static void clear_log_record(struct log_record *log)
     ++static void clear_reftable_log_record(struct reftable_log_record *log)
      +{
      +	log->old_hash = NULL;
      +	log->new_hash = NULL;
      +	log->message = NULL;
      +	log->ref_name = NULL;
     -+	log_record_clear(log);
     ++	reftable_log_record_clear(log);
      +}
      +
     -+static void fill_log_record(struct log_record *log)
     ++static void fill_reftable_log_record(struct reftable_log_record *log)
      +{
      +	const char *info = git_committer_info(0);
      +	struct ident_split split = {};
     @@ -413,7 +416,7 @@ $^
      +	int sign = 1;
      +	assert(0 == result);
      +
     -+	log_record_clear(log);
     ++	reftable_log_record_clear(log);
      +	log->name =
      +		xstrndup(split.name_begin, split.name_end - split.name_begin);
      +	log->email =
     @@ -431,12 +434,12 @@ $^
      +	log->tz_offset = sign * atoi(split.tz_begin);
      +}
      +
     -+static struct ref_store *reftable_ref_store_create(const char *path,
     ++static struct ref_store *git_reftable_ref_store_create(const char *path,
      +						   unsigned int store_flags)
      +{
     -+	struct reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
     ++	struct git_reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
      +	struct ref_store *ref_store = (struct ref_store *)refs;
     -+	struct write_options cfg = {
     ++	struct reftable_write_options cfg = {
      +		.block_size = 4096,
      +		.hash_id = the_hash_algo->format_id,
      +	};
     @@ -449,10 +452,6 @@ $^
      +	refs->reftable_dir = xstrdup(sb.buf);
      +	strbuf_reset(&sb);
      +
     -+	strbuf_addf(&sb, "%s/reftable/tables.list", path);
     -+	refs->table_list_file = xstrdup(sb.buf);
     -+	strbuf_reset(&sb);
     -+
      +	strbuf_addf(&sb, "%s/refs", path);
      +	safe_create_dir(sb.buf, 1);
      +	strbuf_reset(&sb);
     @@ -464,31 +463,23 @@ $^
      +	strbuf_addf(&sb, "%s/refs/heads", path);
      +	write_file(sb.buf, "this repository uses the reftable format");
      +
     -+	refs->err = new_stack(&refs->stack, refs->reftable_dir,
     -+			      refs->table_list_file, cfg);
     ++	refs->err = reftable_new_stack(&refs->stack, refs->reftable_dir, cfg);
      +	strbuf_release(&sb);
      +	return ref_store;
      +}
      +
      +static int reftable_init_db(struct ref_store *ref_store, struct strbuf *err)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	FILE *file;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	safe_create_dir(refs->reftable_dir, 1);
     -+
     -+	file = fopen(refs->table_list_file, "a");
     -+	if (file == NULL) {
     -+		return -1;
     -+	}
     -+	fclose(file);
      +	return 0;
      +}
      +
     -+struct reftable_iterator {
     ++struct git_reftable_iterator {
      +	struct ref_iterator base;
     -+	struct iterator iter;
     -+	struct ref_record ref;
     ++	struct reftable_iterator iter;
     ++	struct reftable_ref_record ref;
      +	struct object_id oid;
      +	struct ref_store *ref_store;
      +	unsigned int flags;
     @@ -498,9 +489,9 @@ $^
      +
      +static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
      +{
     -+	struct reftable_iterator *ri = (struct reftable_iterator *)ref_iterator;
     ++	struct git_reftable_iterator *ri = (struct git_reftable_iterator *)ref_iterator;
      +	while (ri->err == 0) {
     -+		ri->err = iterator_next_ref(ri->iter, &ri->ref);
     ++		ri->err = reftable_iterator_next_ref(ri->iter, &ri->ref);
      +		if (ri->err) {
      +			break;
      +		}
     @@ -554,7 +545,7 @@ $^
      +static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
      +				      struct object_id *peeled)
      +{
     -+	struct reftable_iterator *ri = (struct reftable_iterator *)ref_iterator;
     ++	struct git_reftable_iterator *ri = (struct git_reftable_iterator *)ref_iterator;
      +	if (ri->ref.target_value != NULL) {
      +		hashcpy(peeled->hash, ri->ref.target_value);
      +		return 0;
     @@ -565,9 +556,9 @@ $^
      +
      +static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
      +{
     -+	struct reftable_iterator *ri = (struct reftable_iterator *)ref_iterator;
     -+	ref_record_clear(&ri->ref);
     -+	iterator_destroy(&ri->iter);
     ++	struct git_reftable_iterator *ri = (struct git_reftable_iterator *)ref_iterator;
     ++	reftable_ref_record_clear(&ri->ref);
     ++	reftable_iterator_destroy(&ri->iter);
      +	return 0;
      +}
      +
     @@ -580,16 +571,16 @@ $^
      +reftable_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
      +			    unsigned int flags)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	struct reftable_iterator *ri = xcalloc(1, sizeof(*ri));
     -+	struct merged_table *mt = NULL;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
     ++	struct git_reftable_iterator *ri = xcalloc(1, sizeof(*ri));
     ++	struct reftable_merged_table *mt = NULL;
      +
      +	if (refs->err < 0) {
      +		ri->err = refs->err;
      +	} else {
     -+		mt = stack_merged_table(refs->stack);
     -+		ri->err = merged_table_seek_ref(mt, &ri->iter, prefix);
     ++		mt = reftable_stack_merged_table(refs->stack);
     ++		ri->err = reftable_merged_table_seek_ref(mt, &ri->iter, prefix);
      +	}
      +
      +	base_ref_iterator_init(&ri->base, &reftable_ref_iterator_vtable, 1);
     @@ -610,8 +601,8 @@ $^
      +				      struct ref_transaction *transaction,
      +				      struct strbuf *err)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	(void)refs;
      +	return 0;
      +}
     @@ -640,19 +631,19 @@ $^
      +		      ((struct ref_update *)b)->refname);
      +}
      +
     -+static int write_transaction_table(struct writer *writer, void *arg)
     ++static int write_transaction_table(struct reftable_writer *writer, void *arg)
      +{
      +	struct ref_transaction *transaction = (struct ref_transaction *)arg;
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)transaction->ref_store;
     -+	uint64_t ts = stack_next_update_index(refs->stack);
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)transaction->ref_store;
     ++	uint64_t ts = reftable_stack_next_update_index(refs->stack);
      +	int err = 0;
     -+	struct log_record *logs = calloc(transaction->nr, sizeof(*logs));
     ++	struct reftable_log_record *logs = calloc(transaction->nr, sizeof(*logs));
      +	struct ref_update **sorted =
      +		malloc(transaction->nr * sizeof(struct ref_update *));
      +	COPY_ARRAY(sorted, transaction->updates, transaction->nr);
      +	QSORT(sorted, transaction->nr, ref_update_cmp);
     -+	writer_set_limits(writer, ts, ts);
     ++	reftable_writer_set_limits(writer, ts, ts);
      +
      +	for (int i = 0; i < transaction->nr; i++) {
      +		struct ref_update *u = sorted[i];
     @@ -667,8 +658,8 @@ $^
      +
      +	for (int i = 0; i < transaction->nr; i++) {
      +		struct ref_update *u = sorted[i];
     -+		struct log_record *log = &logs[i];
     -+		fill_log_record(log);
     ++		struct reftable_log_record *log = &logs[i];
     ++		fill_reftable_log_record(log);
      +		log->ref_name = (char *)u->refname;
      +		log->old_hash = u->old_oid.hash;
      +		log->new_hash = u->new_oid.hash;
     @@ -683,13 +674,13 @@ $^
      +			const char *resolved = refs_resolve_ref_unsafe(
      +				transaction->ref_store, u->refname, 0, &out_oid,
      +				&out_flags);
     -+			struct ref_record ref = {};
     ++			struct reftable_ref_record ref = {};
      +			ref.ref_name =
      +				(char *)(resolved ? resolved : u->refname);
      +			log->ref_name = ref.ref_name;
      +			ref.value = u->new_oid.hash;
      +			ref.update_index = ts;
     -+			err = writer_add_ref(writer, &ref);
     ++			err = reftable_writer_add_ref(writer, &ref);
      +			if (err < 0) {
      +				goto exit;
      +			}
     @@ -697,8 +688,8 @@ $^
      +	}
      +
      +	for (int i = 0; i < transaction->nr; i++) {
     -+		err = writer_add_log(writer, &logs[i]);
     -+		clear_log_record(&logs[i]);
     ++		err = reftable_writer_add_log(writer, &logs[i]);
     ++		clear_reftable_log_record(&logs[i]);
      +		if (err < 0) {
      +			goto exit;
      +		}
     @@ -714,17 +705,17 @@ $^
      +				       struct ref_transaction *transaction,
      +				       struct strbuf *errmsg)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	int err = 0;
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
      +
     -+	err = stack_add(refs->stack, &write_transaction_table, transaction);
     ++	err = reftable_stack_add(refs->stack, &write_transaction_table, transaction);
      +	if (err < 0) {
      +		strbuf_addf(errmsg, "reftable: transaction failure %s",
     -+			    error_str(err));
     ++			    reftable_error_str(err));
      +		return -1;
      +	}
      +
     @@ -739,49 +730,49 @@ $^
      +}
      +
      +struct write_delete_refs_arg {
     -+	struct stack *stack;
     ++	struct reftable_stack *stack;
      +	struct string_list *refnames;
      +	const char *logmsg;
      +	unsigned int flags;
      +};
      +
     -+static int write_delete_refs_table(struct writer *writer, void *argv)
     ++static int write_delete_refs_table(struct reftable_writer *writer, void *argv)
      +{
      +	struct write_delete_refs_arg *arg =
      +		(struct write_delete_refs_arg *)argv;
     -+	uint64_t ts = stack_next_update_index(arg->stack);
     ++	uint64_t ts = reftable_stack_next_update_index(arg->stack);
      +	int err = 0;
      +
     -+	writer_set_limits(writer, ts, ts);
     ++	reftable_writer_set_limits(writer, ts, ts);
      +	for (int i = 0; i < arg->refnames->nr; i++) {
     -+		struct ref_record ref = {
     ++		struct reftable_ref_record ref = {
      +			.ref_name = (char *)arg->refnames->items[i].string,
      +			.update_index = ts,
      +		};
     -+		err = writer_add_ref(writer, &ref);
     ++		err = reftable_writer_add_ref(writer, &ref);
      +		if (err < 0) {
      +			return err;
      +		}
      +	}
      +
      +	for (int i = 0; i < arg->refnames->nr; i++) {
     -+		struct log_record log = {};
     -+		struct ref_record current = {};
     -+		fill_log_record(&log);
     ++		struct reftable_log_record log = {};
     ++		struct reftable_ref_record current = {};
     ++		fill_reftable_log_record(&log);
      +		log.message = xstrdup(arg->logmsg);
      +		log.new_hash = NULL;
      +		log.old_hash = NULL;
      +		log.update_index = ts;
      +		log.ref_name = (char *)arg->refnames->items[i].string;
      +
     -+		if (stack_read_ref(arg->stack, log.ref_name, &current) == 0) {
     ++		if (reftable_stack_read_ref(arg->stack, log.ref_name, &current) == 0) {
      +			log.old_hash = current.value;
      +		}
     -+		err = writer_add_log(writer, &log);
     ++		err = reftable_writer_add_log(writer, &log);
      +		log.old_hash = NULL;
     -+		ref_record_clear(&current);
     ++		reftable_ref_record_clear(&current);
      +
     -+		clear_log_record(&log);
     ++		clear_reftable_log_record(&log);
      +		if (err < 0) {
      +			return err;
      +		}
     @@ -793,8 +784,8 @@ $^
      +				struct string_list *refnames,
      +				unsigned int flags)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	struct write_delete_refs_arg arg = {
      +		.stack = refs->stack,
      +		.refnames = refnames,
     @@ -805,52 +796,52 @@ $^
      +		return refs->err;
      +	}
      +
     -+	return stack_add(refs->stack, &write_delete_refs_table, &arg);
     ++	return reftable_stack_add(refs->stack, &write_delete_refs_table, &arg);
      +}
      +
      +static int reftable_pack_refs(struct ref_store *ref_store, unsigned int flags)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
     -+	return stack_compact_all(refs->stack, NULL);
     ++	return reftable_stack_compact_all(refs->stack, NULL);
      +}
      +
      +struct write_create_symref_arg {
     -+	struct reftable_ref_store *refs;
     ++	struct git_reftable_ref_store *refs;
      +	const char *refname;
      +	const char *target;
      +	const char *logmsg;
      +};
      +
     -+static int write_create_symref_table(struct writer *writer, void *arg)
     ++static int write_create_symref_table(struct reftable_writer *writer, void *arg)
      +{
      +	struct write_create_symref_arg *create =
      +		(struct write_create_symref_arg *)arg;
     -+	uint64_t ts = stack_next_update_index(create->refs->stack);
     ++	uint64_t ts = reftable_stack_next_update_index(create->refs->stack);
      +	int err = 0;
      +
     -+	struct ref_record ref = {
     ++	struct reftable_ref_record ref = {
      +		.ref_name = (char *)create->refname,
      +		.target = (char *)create->target,
      +		.update_index = ts,
      +	};
     -+	writer_set_limits(writer, ts, ts);
     -+	err = writer_add_ref(writer, &ref);
     ++	reftable_writer_set_limits(writer, ts, ts);
     ++	err = reftable_writer_add_ref(writer, &ref);
      +	if (err < 0) {
      +		return err;
      +	}
      +
      +	{
     -+		struct log_record log = {};
     ++		struct reftable_log_record log = {};
      +		struct object_id new_oid = {};
      +		struct object_id old_oid = {};
     -+		struct ref_record current = {};
     -+		stack_read_ref(create->refs->stack, create->refname, &current);
     ++		struct reftable_ref_record current = {};
     ++		reftable_stack_read_ref(create->refs->stack, create->refname, &current);
      +
     -+		fill_log_record(&log);
     ++		fill_reftable_log_record(&log);
      +		log.ref_name = current.ref_name;
      +		if (refs_resolve_ref_unsafe(
      +			    (struct ref_store *)create->refs, create->refname,
     @@ -865,12 +856,12 @@ $^
      +		}
      +
      +		if (log.old_hash != NULL || log.new_hash != NULL) {
     -+			writer_add_log(writer, &log);
     ++			reftable_writer_add_log(writer, &log);
      +		}
      +		log.ref_name = NULL;
      +		log.old_hash = NULL;
      +		log.new_hash = NULL;
     -+		clear_log_record(&log);
     ++		clear_reftable_log_record(&log);
      +	}
      +	return 0;
      +}
     @@ -879,8 +870,8 @@ $^
      +				  const char *refname, const char *target,
      +				  const char *logmsg)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	struct write_create_symref_arg arg = { .refs = refs,
      +					       .refname = refname,
      +					       .target = target,
     @@ -888,55 +879,55 @@ $^
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
     -+	return stack_add(refs->stack, &write_create_symref_table, &arg);
     ++	return reftable_stack_add(refs->stack, &write_create_symref_table, &arg);
      +}
      +
      +struct write_rename_arg {
     -+	struct stack *stack;
     ++	struct reftable_stack *stack;
      +	const char *oldname;
      +	const char *newname;
      +	const char *logmsg;
      +};
      +
     -+static int write_rename_table(struct writer *writer, void *argv)
     ++static int write_rename_table(struct reftable_writer *writer, void *argv)
      +{
      +	struct write_rename_arg *arg = (struct write_rename_arg *)argv;
     -+	uint64_t ts = stack_next_update_index(arg->stack);
     -+	struct ref_record ref = {};
     -+	int err = stack_read_ref(arg->stack, arg->oldname, &ref);
     ++	uint64_t ts = reftable_stack_next_update_index(arg->stack);
     ++	struct reftable_ref_record ref = {};
     ++	int err = reftable_stack_read_ref(arg->stack, arg->oldname, &ref);
      +
      +	if (err) {
      +		goto exit;
      +	}
      +
      +	/* XXX do ref renames overwrite the target? */
     -+	if (stack_read_ref(arg->stack, arg->newname, &ref) == 0) {
     ++	if (reftable_stack_read_ref(arg->stack, arg->newname, &ref) == 0) {
      +		goto exit;
      +	}
      +
      +	free(ref.ref_name);
      +	ref.ref_name = strdup(arg->newname);
     -+	writer_set_limits(writer, ts, ts);
     ++	reftable_writer_set_limits(writer, ts, ts);
      +	ref.update_index = ts;
      +
      +	{
     -+		struct ref_record todo[2] = {};
     ++		struct reftable_ref_record todo[2] = {};
      +		todo[0].ref_name = (char *)arg->oldname;
      +		todo[0].update_index = ts;
      +		/* leave todo[0] empty */
      +		todo[1] = ref;
      +		todo[1].update_index = ts;
      +
     -+		err = writer_add_refs(writer, todo, 2);
     ++		err = reftable_writer_add_refs(writer, todo, 2);
      +		if (err < 0) {
      +			goto exit;
      +		}
      +	}
      +
      +	if (ref.value != NULL) {
     -+		struct log_record todo[2] = {};
     -+		fill_log_record(&todo[0]);
     -+		fill_log_record(&todo[1]);
     ++		struct reftable_log_record todo[2] = {};
     ++		fill_reftable_log_record(&todo[0]);
     ++		fill_reftable_log_record(&todo[1]);
      +
      +		todo[0].ref_name = (char *)arg->oldname;
      +		todo[0].update_index = ts;
     @@ -950,10 +941,10 @@ $^
      +		todo[1].new_hash = ref.value;
      +		todo[1].message = (char *)arg->logmsg;
      +
     -+		err = writer_add_logs(writer, todo, 2);
     ++		err = reftable_writer_add_logs(writer, todo, 2);
      +
     -+		clear_log_record(&todo[0]);
     -+		clear_log_record(&todo[1]);
     ++		clear_reftable_log_record(&todo[0]);
     ++		clear_reftable_log_record(&todo[1]);
      +
      +		if (err < 0) {
      +			goto exit;
     @@ -964,7 +955,7 @@ $^
      +	}
      +
      +exit:
     -+	ref_record_clear(&ref);
     ++	reftable_ref_record_clear(&ref);
      +	return err;
      +}
      +
     @@ -972,8 +963,8 @@ $^
      +			       const char *oldrefname, const char *newrefname,
      +			       const char *logmsg)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +	struct write_rename_arg arg = {
      +		.stack = refs->stack,
      +		.oldname = oldrefname,
     @@ -984,7 +975,7 @@ $^
      +		return refs->err;
      +	}
      +
     -+	return stack_add(refs->stack, &write_rename_table, &arg);
     ++	return reftable_stack_add(refs->stack, &write_rename_table, &arg);
      +}
      +
      +static int reftable_copy_ref(struct ref_store *ref_store,
     @@ -996,8 +987,8 @@ $^
      +
      +struct reftable_reflog_ref_iterator {
      +	struct ref_iterator base;
     -+	struct iterator iter;
     -+	struct log_record log;
     ++	struct reftable_iterator iter;
     ++	struct reftable_log_record log;
      +	struct object_id oid;
      +	char *last_name;
      +};
     @@ -1009,7 +1000,7 @@ $^
      +		(struct reftable_reflog_ref_iterator *)ref_iterator;
      +
      +	while (1) {
     -+		int err = iterator_next_log(ri->iter, &ri->log);
     ++		int err = reftable_iterator_next_log(ri->iter, &ri->log);
      +		if (err > 0) {
      +			return ITER_DONE;
      +		}
     @@ -1041,8 +1032,8 @@ $^
      +{
      +	struct reftable_reflog_ref_iterator *ri =
      +		(struct reftable_reflog_ref_iterator *)ref_iterator;
     -+	log_record_clear(&ri->log);
     -+	iterator_destroy(&ri->iter);
     ++	reftable_log_record_clear(&ri->log);
     ++	reftable_iterator_destroy(&ri->iter);
      +	return 0;
      +}
      +
     @@ -1055,11 +1046,11 @@ $^
      +reftable_reflog_iterator_begin(struct ref_store *ref_store)
      +{
      +	struct reftable_reflog_ref_iterator *ri = xcalloc(sizeof(*ri), 1);
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
      +
     -+	struct merged_table *mt = stack_merged_table(refs->stack);
     -+	int err = merged_table_seek_log(mt, &ri->iter, "");
     ++	struct reftable_merged_table *mt = reftable_stack_merged_table(refs->stack);
     ++	int err = reftable_merged_table_seek_log(mt, &ri->iter, "");
      +	if (err < 0) {
      +		free(ri);
      +		return NULL;
     @@ -1077,21 +1068,21 @@ $^
      +					  const char *refname,
      +					  each_reflog_ent_fn fn, void *cb_data)
      +{
     -+	struct iterator it = {};
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	struct merged_table *mt = NULL;
     ++	struct reftable_iterator it = {};
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_merged_table *mt = NULL;
      +	int err = 0;
     -+	struct log_record log = {};
     ++	struct reftable_log_record log = {};
      +
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
      +
     -+	mt = stack_merged_table(refs->stack);
     -+	err = merged_table_seek_log(mt, &it, refname);
     ++	mt = reftable_stack_merged_table(refs->stack);
     ++	err = reftable_merged_table_seek_log(mt, &it, refname);
      +	while (err == 0) {
     -+		err = iterator_next_log(it, &log);
     ++		err = reftable_iterator_next_log(it, &log);
      +		if (err != 0) {
      +			break;
      +		}
     @@ -1120,8 +1111,8 @@ $^
      +		}
      +	}
      +
     -+	log_record_clear(&log);
     -+	iterator_destroy(&it);
     ++	reftable_log_record_clear(&log);
     ++	reftable_iterator_destroy(&it);
      +	if (err > 0) {
      +		err = 0;
      +	}
     @@ -1133,11 +1124,11 @@ $^
      +					  const char *refname,
      +					  each_reflog_ent_fn fn, void *cb_data)
      +{
     -+	struct iterator it = {};
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	struct merged_table *mt = NULL;
     -+	struct log_record *logs = NULL;
     ++	struct reftable_iterator it = {};
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_merged_table *mt = NULL;
     ++	struct reftable_log_record *logs = NULL;
      +	int cap = 0;
      +	int len = 0;
      +	int err = 0;
     @@ -1145,12 +1136,12 @@ $^
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
     -+	mt = stack_merged_table(refs->stack);
     -+	err = merged_table_seek_log(mt, &it, refname);
     ++	mt = reftable_stack_merged_table(refs->stack);
     ++	err = reftable_merged_table_seek_log(mt, &it, refname);
      +
      +	while (err == 0) {
     -+		struct log_record log = {};
     -+		err = iterator_next_log(it, &log);
     ++		struct reftable_log_record log = {};
     ++		err = reftable_iterator_next_log(it, &log);
      +		if (err != 0) {
      +			break;
      +		}
     @@ -1168,7 +1159,7 @@ $^
      +	}
      +
      +	for (int i = len; i--;) {
     -+		struct log_record *log = &logs[i];
     ++		struct reftable_log_record *log = &logs[i];
      +		struct object_id old_oid = {};
      +		struct object_id new_oid = {};
      +		const char *full_committer = "";
     @@ -1187,11 +1178,11 @@ $^
      +	}
      +
      +	for (int i = 0; i < len; i++) {
     -+		log_record_clear(&logs[i]);
     ++		reftable_log_record_clear(&logs[i]);
      +	}
      +	free(logs);
      +
     -+	iterator_destroy(&it);
     ++	reftable_iterator_destroy(&it);
      +	if (err > 0) {
      +		err = 0;
      +	}
     @@ -1219,8 +1210,8 @@ $^
      +}
      +
      +struct reflog_expiry_arg {
     -+	struct reftable_ref_store *refs;
     -+	struct log_record *tombstones;
     ++	struct git_reftable_ref_store *refs;
     ++	struct reftable_log_record *tombstones;
      +	int len;
      +	int cap;
      +};
     @@ -1229,7 +1220,7 @@ $^
      +{
      +	int i = 0;
      +	for (; i < arg->len; i++) {
     -+		log_record_clear(&arg->tombstones[i]);
     ++		reftable_log_record_clear(&arg->tombstones[i]);
      +	}
      +
      +	FREE_AND_NULL(arg->tombstones);
     @@ -1238,7 +1229,7 @@ $^
      +static void add_log_tombstone(struct reflog_expiry_arg *arg,
      +			      const char *refname, uint64_t ts)
      +{
     -+	struct log_record tombstone = {
     ++	struct reftable_log_record tombstone = {
      +		.ref_name = xstrdup(refname),
      +		.update_index = ts,
      +	};
     @@ -1250,14 +1241,14 @@ $^
      +	arg->tombstones[arg->len++] = tombstone;
      +}
      +
     -+static int write_reflog_expiry_table(struct writer *writer, void *argv)
     ++static int write_reflog_expiry_table(struct reftable_writer *writer, void *argv)
      +{
      +	struct reflog_expiry_arg *arg = (struct reflog_expiry_arg *)argv;
     -+	uint64_t ts = stack_next_update_index(arg->refs->stack);
     ++	uint64_t ts = reftable_stack_next_update_index(arg->refs->stack);
      +	int i = 0;
     -+	writer_set_limits(writer, ts, ts);
     ++	reftable_writer_set_limits(writer, ts, ts);
      +	for (i = 0; i < arg->len; i++) {
     -+		int err = writer_add_log(writer, &arg->tombstones[i]);
     ++		int err = reftable_writer_add_log(writer, &arg->tombstones[i]);
      +		if (err) {
      +			return err;
      +		}
     @@ -1286,21 +1277,21 @@ $^
      +	  It would be better if the refs backend supported an API that sets a
      +	  criterion for all refs, passing the criterion to pack_refs().
      +	*/
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	struct merged_table *mt = NULL;
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_merged_table *mt = NULL;
      +	struct reflog_expiry_arg arg = {
      +		.refs = refs,
      +	};
     -+	struct log_record log = {};
     -+	struct iterator it = {};
     ++	struct reftable_log_record log = {};
     ++	struct reftable_iterator it = {};
      +	int err = 0;
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
      +
     -+	mt = stack_merged_table(refs->stack);
     -+	err = merged_table_seek_log(mt, &it, refname);
     ++	mt = reftable_stack_merged_table(refs->stack);
     ++	err = reftable_merged_table_seek_log(mt, &it, refname);
      +	if (err < 0) {
      +		return err;
      +	}
     @@ -1309,7 +1300,7 @@ $^
      +		struct object_id ooid = {};
      +		struct object_id noid = {};
      +
     -+		int err = iterator_next_log(it, &log);
     ++		int err = reftable_iterator_next_log(it, &log);
      +		if (err < 0) {
      +			return err;
      +		}
     @@ -1326,9 +1317,9 @@ $^
      +			add_log_tombstone(&arg, refname, log.update_index);
      +		}
      +	}
     -+	log_record_clear(&log);
     -+	iterator_destroy(&it);
     -+	err = stack_add(refs->stack, &write_reflog_expiry_table, &arg);
     ++	reftable_log_record_clear(&log);
     ++	reftable_iterator_destroy(&it);
     ++	err = reftable_stack_add(refs->stack, &write_reflog_expiry_table, &arg);
      +	clear_log_tombstones(&arg);
      +	return err;
      +}
     @@ -1337,15 +1328,15 @@ $^
      +				 const char *refname, struct object_id *oid,
      +				 struct strbuf *referent, unsigned int *type)
      +{
     -+	struct reftable_ref_store *refs =
     -+		(struct reftable_ref_store *)ref_store;
     -+	struct ref_record ref = {};
     ++	struct git_reftable_ref_store *refs =
     ++		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_ref_record ref = {};
      +	int err = 0;
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
      +
     -+	err = stack_read_ref(refs->stack, refname, &ref);
     ++	err = reftable_stack_read_ref(refs->stack, refname, &ref);
      +	if (err) {
      +		goto exit;
      +	}
     @@ -1358,14 +1349,14 @@ $^
      +		hashcpy(oid->hash, ref.value);
      +	}
      +exit:
     -+	ref_record_clear(&ref);
     ++	reftable_ref_record_clear(&ref);
      +	return err;
      +}
      +
      +struct ref_storage_be refs_be_reftable = {
      +	&refs_be_files,
      +	"reftable",
     -+	reftable_ref_store_create,
     ++	git_reftable_ref_store_create,
      +	reftable_init_db,
      +	reftable_transaction_prepare,
      +	reftable_transaction_finish,
     @@ -1471,24 +1462,28 @@ $^
      +. ./test-lib.sh
      +
      +test_expect_success 'basic operation of reftable storage' '
     -+        git init --ref-storage=reftable repo &&
     -+        cd repo &&
     -+        echo "hello" > world.txt &&
     -+        git add world.txt &&
     -+        git commit -m "first post" &&
     -+        printf "HEAD\nrefs/heads/master\n" > want &&
     -+        git show-ref | cut -f2 -d" " > got &&
     -+        test_cmp got want &&
     -+        for count in $(test_seq 1 10); do
     -+                echo "hello" >> world.txt
     -+                git commit -m "number ${count}" world.txt
     -+        done &&
     -+        git gc &&
     -+        nfiles=$(ls -1 .git/reftable | wc -l | tr -d "[ \t]" ) &&
     -+        test "${nfiles}" = "2" &&
     -+        git reflog refs/heads/master > output &&
     -+        grep "commit (initial): first post" output &&
     -+        grep "commit: number 10" output
     ++	git init --ref-storage=reftable repo && (
     ++	cd repo &&
     ++	echo "hello" >world.txt &&
     ++	git add world.txt &&
     ++	git commit -m "first post" &&
     ++	test_write_lines HEAD refs/heads/master >expect &&
     ++	git show-ref &&
     ++	git show-ref | cut -f2 -d" " > actual &&
     ++	test_cmp actual expect &&
     ++	for count in $(test_seq 1 10)
     ++	do
     ++		echo "hello" >>world.txt
     ++		git commit -m "number ${count}" world.txt ||
     ++		return 1
     ++	done &&
     ++	git gc &&
     ++	nfiles=$(ls -1 .git/reftable | wc -l ) &&
     ++	test ${nfiles} = "2" &&
     ++	git reflog refs/heads/master >output &&
     ++	test_line_count = 11 output &&
     ++	grep "commit (initial): first post" output &&
     ++	grep "commit: number 10" output )
      +'
      +
      +test_done

-- 
gitgitgadget




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux