+++ /dev/null
-#include "refs.h"
-#include "cache.h"
-#include "rev-cache.h"
-
-struct rev_cache **rev_cache;
-int nr_revs, alloc_revs;
-
-static struct rev_list_elem *rle_free;
-
-#define BATCH_SIZE 512
-
-int find_rev_cache(const unsigned char *sha1)
-{
- int lo = 0, hi = nr_revs;
- while (lo < hi) {
- int mi = (lo + hi) / 2;
- struct rev_cache *ri = rev_cache[mi];
- int cmp = memcmp(sha1, ri->sha1, 20);
- if (!cmp)
- return mi;
- if (cmp < 0)
- hi = mi;
- else
- lo = mi + 1;
- }
- return -lo - 1;
-}
-
-static struct rev_list_elem *alloc_list_elem(void)
-{
- struct rev_list_elem *rle;
- if (!rle_free) {
- int i;
-
- rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
- for (i = 0; i < BATCH_SIZE - 1; i++) {
- rle[i].ri = NULL;
- rle[i].next = &rle[i + 1];
- }
- rle[BATCH_SIZE - 1].ri = NULL;
- rle[BATCH_SIZE - 1].next = NULL;
- rle_free = rle;
- }
- rle = rle_free;
- rle_free = rle->next;
- return rle;
-}
-
-static struct rev_cache *create_rev_cache(const unsigned char *sha1)
-{
- struct rev_cache *ri;
- int pos = find_rev_cache(sha1);
-
- if (0 <= pos)
- return rev_cache[pos];
- pos = -pos - 1;
- if (alloc_revs <= ++nr_revs) {
- alloc_revs = alloc_nr(alloc_revs);
- rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
- }
- if (pos < nr_revs)
- memmove(rev_cache + pos + 1, rev_cache + pos,
- (nr_revs - pos - 1) * sizeof(ri));
- ri = xcalloc(1, sizeof(*ri));
- memcpy(ri->sha1, sha1, 20);
- rev_cache[pos] = ri;
- return ri;
-}
-
-static unsigned char last_sha1[20];
-
-static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
-{
- unsigned char flag;
- struct rev_list_elem *rle;
-
- if (ri->written)
- return;
-
- if (ri->parsed) {
- /* We use last_sha1 compression only for the first parent;
- * otherwise the resulting rev-cache would lose the parent
- * order information.
- */
- if (ri->parents &&
- !memcmp(ri->parents->ri->sha1, last_sha1, 20))
- flag = (ri->num_parents - 1) | 0x80;
- else
- flag = ri->num_parents;
-
- fwrite(ri->sha1, 20, 1, rev_cache_file);
- fwrite(&flag, 1, 1, rev_cache_file);
- for (rle = ri->parents; rle; rle = rle->next) {
- if (flag & 0x80 && rle == ri->parents)
- continue;
- fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
- }
- memcpy(last_sha1, ri->sha1, 20);
- ri->written = 1;
- }
- /* recursively write children depth first */
- for (rle = ri->children; rle; rle = rle->next)
- write_one_rev_cache(rev_cache_file, rle->ri);
-}
-
-void write_rev_cache(const char *newpath, const char *oldpath)
-{
- /* write the following commit ancestry information in
- * $GIT_DIR/info/rev-cache.
- *
- * The format is:
- * 20-byte SHA1 (commit ID)
- * 1-byte flag:
- * - bit 0-6 records "number of parent commit SHA1s to
- * follow" (i.e. up to 127 children can be listed).
- * - when the bit 7 is on, then "the entry immediately
- * before this entry is one of the parents of this
- * commit".
- * N x 20-byte SHA1 (parent commit IDs)
- */
- FILE *rev_cache_file;
- int i;
- struct rev_cache *ri;
-
- if (!strcmp(newpath, oldpath)) {
- /* If we are doing it in place */
- rev_cache_file = fopen(newpath, "a");
- }
- else {
- char buf[8096];
- size_t sz;
- FILE *oldfp = fopen(oldpath, "r");
- rev_cache_file = fopen(newpath, "w");
- if (oldfp) {
- while (1) {
- sz = fread(buf, 1, sizeof(buf), oldfp);
- if (sz == 0)
- break;
- fwrite(buf, 1, sz, rev_cache_file);
- }
- fclose(oldfp);
- }
- }
-
- memset(last_sha1, 0, 20);
-
- /* Go through available rev_cache structures, starting from
- * parentless ones first, so that we would get most out of
- * last_sha1 optimization by the depth first behaviour of
- * write_one_rev_cache().
- */
- for (i = 0; i < nr_revs; i++) {
- ri = rev_cache[i];
- if (ri->num_parents)
- continue;
- write_one_rev_cache(rev_cache_file, ri);
- }
- /* Then the rest */
- for (i = 0; i < nr_revs; i++) {
- ri = rev_cache[i];
- write_one_rev_cache(rev_cache_file, ri);
- }
- fclose(rev_cache_file);
-}
-
-static void add_parent(struct rev_cache *child,
- const unsigned char *parent_sha1)
-{
- struct rev_cache *parent = create_rev_cache(parent_sha1);
- struct rev_list_elem *e = alloc_list_elem();
-
- /* Keep the parent list ordered in the same way the commit
- * object records them.
- */
- e->ri = parent;
- e->next = NULL;
- if (!child->parents_tail)
- child->parents = e;
- else
- child->parents_tail->next = e;
- child->parents_tail = e;
- child->num_parents++;
-
- /* There is no inherent order of the children so we just
- * LIFO them together.
- */
- e = alloc_list_elem();
- e->next = parent->children;
- parent->children = e;
- e->ri = child;
- parent->num_children++;
-}
-
-int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
-{
- unsigned char *map;
- int fd;
- struct stat st;
- unsigned long ofs, len;
- struct rev_cache *ri = NULL;
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- if (dry_run)
- return error("cannot open %s", path);
- if (errno == ENOENT)
- return 0;
- return -1;
- }
- if (fstat(fd, &st)) {
- close(fd);
- return -1;
- }
- map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- close(fd);
- if (map == MAP_FAILED)
- return -1;
-
- memset(last_sha1, 0, 20);
- ofs = 0;
- len = st.st_size;
- while (ofs < len) {
- unsigned char sha1[20];
- int flag, cnt, i;
- if (len < ofs + 21)
- die("rev-cache too short");
- memcpy(sha1, map + ofs, 20);
- flag = map[ofs + 20];
- ofs += 21;
- cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
- if (len < ofs + (flag & 0x7f) * 20)
- die("rev-cache too short to have %d more parents",
- (flag & 0x7f));
- if (dumpfile)
- fprintf(dumpfile, "%s", sha1_to_hex(sha1));
- if (!dry_run) {
- ri = create_rev_cache(sha1);
- if (!ri)
- die("cannot create rev-cache for %s",
- sha1_to_hex(sha1));
- ri->written = ri->parsed = 1;
- }
- i = 0;
- if (flag & 0x80) {
- if (!dry_run)
- add_parent(ri, last_sha1);
- if (dumpfile)
- fprintf(dumpfile, " %s",
- sha1_to_hex(last_sha1));
- i++;
- }
- while (i++ < cnt) {
- if (!dry_run)
- add_parent(ri, map + ofs);
- if (dumpfile)
- fprintf(dumpfile, " %s",
- sha1_to_hex(last_sha1));
- ofs += 20;
- }
- if (dumpfile)
- fprintf(dumpfile, "\n");
- memcpy(last_sha1, sha1, 20);
- }
- if (ofs != len)
- die("rev-cache truncated?");
- munmap(map, len);
- return 0;
-}
-
-int record_rev_cache(const unsigned char *sha1, FILE *dumpfile)
-{
- unsigned char parent[20];
- char type[20];
- unsigned long size, ofs;
- unsigned int cnt, i;
- void *buf;
- struct rev_cache *ri;
-
- buf = read_sha1_file(sha1, type, &size);
- if (!buf)
- return error("%s: not found", sha1_to_hex(sha1));
- if (strcmp(type, "commit")) {
- free(buf);
- return error("%s: not a commit but a %s",
- sha1_to_hex(sha1), type);
- }
- ri = create_rev_cache(sha1);
- if (ri->parsed)
- return 0;
- if (dumpfile)
- fprintf(dumpfile, "commit %s\n", sha1_to_hex(sha1));
-
- cnt = 0;
- ofs = 46; /* "tree " + hex-sha1 + "\n" */
- while (!memcmp(buf + ofs, "parent ", 7) &&
- !get_sha1_hex(buf + ofs + 7, parent)) {
- ofs += 48;
- cnt++;
- }
- if (cnt * 48 + 46 != ofs) {
- free(buf);
- die("internal error in record_rev_cache");
- }
-
- ri = create_rev_cache(sha1);
- ri->parsed = 1;
-
- for (i = 0; i < cnt; i++) {
- unsigned char parent_sha1[20];
-
- ofs = 46 + i * 48 + 7;
- get_sha1_hex(buf + ofs, parent_sha1);
- add_parent(ri, parent_sha1);
- record_rev_cache(parent_sha1, dumpfile);
- }
- free(buf);
- return 0;
-}