commit - 33acf1a27bbf8e5a0f4eabe051384ba0d5043600
commit + b79280dd9fee6141825026119fa247f1a0ecb334
blob - 8c74017dc075cbe01de88fbcfc91baad551447ae
blob + 442a2ede6da8df0508a3bfa7c3a7090c4087e465
--- lib/pack_create.c
+++ lib/pack_create.c
#include "got_lib_privsep.h"
#include "got_lib_repository.h"
+#ifndef MIN
+#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
#ifndef MAX
#define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
#endif
/* The best delta we picked */
struct got_pack_meta *head;
struct got_pack_meta *prev;
- struct got_delta_instruction *deltas;
- int ndeltas;
+ off_t delta_offset; /* offset in delta cache file */
+ off_t delta_len; /* length in delta cache file */
int nchain;
/* Only used for delta window */
{
if (meta == NULL)
return;
- free(meta->deltas);
- meta->deltas = NULL;
free(meta->path);
meta->path = NULL;
}
return size;
}
+static const struct got_error *
+encode_delta(struct got_pack_meta *m, struct got_raw_object *o,
+ struct got_delta_instruction *deltas, int ndeltas,
+ off_t base_size, FILE *f);
static const struct got_error *
pick_deltas(struct got_pack_meta **meta, int nmeta, int nours,
- struct got_repository *repo,
+ FILE *delta_cache, struct got_repository *repo,
got_pack_progress_cb progress_cb, void *progress_arg,
got_cancel_cb cancel_cb, void *cancel_arg)
{
const struct got_error *err = NULL;
struct got_pack_meta *m = NULL, *base = NULL;
struct got_raw_object *raw = NULL, *base_raw = NULL;
- struct got_delta_instruction *deltas;
- int i, j, size, ndeltas, best;
+ struct got_delta_instruction *deltas = NULL, *best_deltas = NULL;
+ int i, j, size, best_size, ndeltas, best_ndeltas;
const int max_base_candidates = 10;
int outfd = -1;
goto done;
}
m = meta[i];
- m->deltas = NULL;
- m->ndeltas = 0;
if (m->obj_type == GOT_OBJ_TYPE_COMMIT ||
m->obj_type == GOT_OBJ_TYPE_TAG)
n->dtab = NULL;
}
- best = raw->size;
+ best_size = raw->size;
+ best_ndeltas = 0;
for (j = MAX(0, i - max_base_candidates); j < i; j++) {
if (cancel_cb) {
err = (*cancel_cb)(cancel_arg);
goto done;
size = delta_size(deltas, ndeltas);
- if (size + 32 < best){
+ if (size + 32 < best_size){
/*
* if we already picked a best delta,
* replace it.
*/
- free(m->deltas);
- best = size;
- m->deltas = deltas;
- m->ndeltas = ndeltas;
+ best_size = size;
+ free(best_deltas);
+ best_deltas = deltas;
+ best_ndeltas = ndeltas;
+ deltas = NULL;
m->nchain = base->nchain + 1;
m->prev = base;
m->head = base->head;
}
}
+ if (best_ndeltas > 0) {
+ m->delta_offset = ftello(delta_cache);
+ err = encode_delta(m, raw, best_deltas,
+ best_ndeltas, m->prev->size, delta_cache);
+ free(best_deltas);
+ best_deltas = NULL;
+ best_ndeltas = 0;
+ if (err)
+ goto done;
+ m->delta_len = ftello(delta_cache) - m->delta_offset;
+ }
+
got_object_raw_close(raw);
raw = NULL;
}
got_object_raw_close(base_raw);
if (outfd != -1 && close(outfd) == -1 && err == NULL)
err = got_error_from_errno("close");
+ free(deltas);
+ free(best_deltas);
return err;
}
}
static const struct got_error *
-encodedelta(struct got_pack_meta *m, struct got_raw_object *o,
+encode_delta(struct got_pack_meta *m, struct got_raw_object *o,
+ struct got_delta_instruction *deltas, int ndeltas,
off_t base_size, FILE *f)
{
unsigned char buf[16], *bp;
if (w != i)
return got_ferror(f, GOT_ERR_IO);
- for (j = 0; j < m->ndeltas; j++) {
- d = &m->deltas[j];
+ for (j = 0; j < ndeltas; j++) {
+ d = &deltas[j];
if (d->copy) {
n = d->offset;
bp = &buf[1];
}
static const struct got_error *
-genpack(uint8_t *pack_sha1, FILE *packfile,
+genpack(uint8_t *pack_sha1, FILE *packfile, FILE *delta_cache,
struct got_pack_meta **meta, int nmeta, int nours,
int use_offset_deltas, struct got_repository *repo,
got_pack_progress_cb progress_cb, void *progress_arg,
{
const struct got_error *err = NULL;
int i, nh;
- off_t nd;
SHA1_CTX ctx;
struct got_pack_meta *m;
struct got_raw_object *raw = NULL;
err = got_object_raw_open(&raw, &outfd, repo, &m->id);
if (err)
goto done;
- if (m->deltas == NULL) {
+ if (m->delta_len == 0) {
err = packhdr(&nh, buf, sizeof(buf),
m->obj_type, raw->size);
if (err)
goto done;
packfile_size += outlen;
} else {
+ off_t remain;
if (delta_file == NULL) {
delta_file = got_opentemp();
if (delta_file == NULL) {
err = got_error_from_errno("fseeko");
goto done;
}
- err = encodedelta(m, raw, m->prev->size, delta_file);
- if (err)
- goto done;
- nd = ftello(delta_file);
- if (fseeko(delta_file, 0L, SEEK_SET) == -1) {
+ if (fseeko(delta_cache, m->delta_offset, SEEK_SET)
+ == -1) {
err = got_error_from_errno("fseeko");
goto done;
}
+ remain = m->delta_len;
+ while (remain > 0) {
+ char delta_buf[8192];
+ size_t r, w, n;
+ n = MIN(remain, sizeof(delta_buf));
+ r = fread(delta_buf, 1, n, delta_cache);
+ if (r != n) {
+ err = got_ferror(delta_cache,
+ GOT_ERR_IO);
+ goto done;
+ }
+ w = fwrite(delta_buf, 1, n, delta_file);
+ if (w != n) {
+ err = got_ferror(delta_file,
+ GOT_ERR_IO);
+ goto done;
+ }
+ remain -= n;
+ }
if (use_offset_deltas && m->prev->off != 0) {
err = packhdr(&nh, buf, sizeof(buf),
- GOT_OBJ_TYPE_OFFSET_DELTA, nd);
+ GOT_OBJ_TYPE_OFFSET_DELTA, m->delta_len);
if (err)
goto done;
nh += packoff(buf + nh,
packfile_size += nh;
} else {
err = packhdr(&nh, buf, sizeof(buf),
- GOT_OBJ_TYPE_REF_DELTA, nd);
+ GOT_OBJ_TYPE_REF_DELTA, m->delta_len);
err = hwrite(packfile, buf, nh, &ctx);
if (err)
goto done;
if (err)
goto done;
}
+ if (fseeko(delta_file, 0L, SEEK_SET) == -1) {
+ err = got_error_from_errno("fseeko");
+ goto done;
+ }
err = got_deflate_to_file(&outlen, delta_file,
packfile, &csum);
if (err)
const struct got_error *err;
struct got_pack_meta **meta;
int nmeta;
+ FILE *delta_cache = NULL;
err = read_meta(&meta, &nmeta, theirs, ntheirs, ours, nours, repo,
loose_obj_only, progress_cb, progress_arg, cancel_cb, cancel_arg);
err = got_error(GOT_ERR_CANNOT_PACK);
goto done;
}
+
+ delta_cache = got_opentemp();
+ if (delta_cache == NULL) {
+ err = got_error_from_errno("got_opentemp");
+ goto done;
+ }
+
if (nmeta > 0) {
- err = pick_deltas(meta, nmeta, nours, repo,
+ err = pick_deltas(meta, nmeta, nours, delta_cache, repo,
progress_cb, progress_arg, cancel_cb, cancel_arg);
if (err)
goto done;
+ if (fseeko(delta_cache, 0L, SEEK_SET) == -1) {
+ err = got_error_from_errno("fseeko");
+ goto done;
+ }
}
- err = genpack(packsha1, packfile, meta, nmeta, nours, 1, repo,
- progress_cb, progress_arg, cancel_cb, cancel_arg);
+ err = genpack(packsha1, packfile, delta_cache, meta, nmeta, nours, 1,
+ repo, progress_cb, progress_arg, cancel_cb, cancel_arg);
if (err)
goto done;
done:
free_nmeta(meta, nmeta);
+ if (delta_cache && fclose(delta_cache) == EOF && err == NULL)
+ err = got_error_from_errno("fclose");
return err;
}