Add a changestoreload() that checks the capacity of the current changestore, and loads in a new change by its hash.
This allows loading changes dynamically as needed so there is no need to preload anything. On our worstcase (check2) test target, the memory usage drops from 140MB to around 50MB, and the number allocations drop from 1204 to 326.
The xrealloc() function cannot zero out new memory, which can cause segfaults because garbage data is treated as non-NULL pointer values and passed to free(). To work around this, we initialize optional values to NULL as needed.
QSQNGA5KZ4BVWE4FUJUMOP6SJRIXAC2PYU6JSRG5KXWLYWZZMAJQC EHVLRMEF6YK5FRIV5V7V6P5RHJPCYKMSW5OVKDXLUEWHEM624FBAC P5CSMRVSVJVOUGGWY7UVP4B3XXNLZDEQVXNL5XOPT2GGB63HXA4QC RRYWNHFE3EIRQYBGMSZRLDGKWHVMDAO42QNKFQ2KVYPDC4IHANTAC PC54CREYZ6MOAPTPUUFV5VD3FMRTT6FGOUMOO25GD6BFZJMSS6BAC CWII6DASI3JOJAA4PXSSVJOEUBT32KTGB3VZXKTUCFXK3KNRH2DAC UM5XFLGIZYSFAP6TFEZR4APDSSHRHZJDQKXPFGKT6LUAK7QXN33QC 5D2IYPL75HEP6JUEILEADSZRRSV72NECT6UQR3PORNDR35I2P5GQC Q7TKZCJP2Z75EICZYKCEZDHKGERSOKZGMTSU3UXETBHTF663T66AC Y26WT3ZFN7KSVXOZ26B5Y2OR4M4VQYQLPMAHPC4O5VIT3ENBISXAC YFBKBUKBX3JB7OCB4D3ZKSLWTP6QWZ36HEE5GZROJE55RK33MZCAC LVX6U4EKYXM6H32X5SZS4UBIM5PW4ND4F4QQOF5EQDX3DUHBYFGAC YDQLW2ZOAH7PZ7HHVTSFUO5IWE6O7FDNXVNIN7GG4TJ3P2B2BM4AC XTVLIC243WZF52NVTNRA3SV3WLE2ZZ5GTFQOK45IOLMXYQMTLOSAC }}}struct change *changestoreget(struct changestore *store, struct hash *hash){size_t i;for (i = 0; i < store->len; i++) {if (hasheq(hash, &store->entries[i].hash))return &store->entries[i].change;}return NULL;}voidchangestoreinit(struct changestore *s, size_t cap){s->entries = xmalloc(sizeof(struct changeentry) * cap);s->cap = cap;s->len = 0;}voidchangestorefree(struct changestore *s){size_t i;struct change *c;/* Free all the entries first */for (i = 0; i < s->len; i++) {c = &s->entries[i].change;hashedfree(&c->hashed);if (c->contents)free(c->contents);}free(s->entries);}voidauthorsfree(struct authors *authors){size_t i, j;struct author *author;for (i = 0; i < authors->len; i++) {author = &authors->map[i];for (j = 0; j < author->len; j++) {free(author->entries[j].key);free(author->entries[j].value);
voidhashedfree(struct hashed *h){free(h->header.message);if (h->header.description)free(h->header.description);free(h->header.timestamp);authorsfree(&h->header.authors);hashlist_free(&h->dependencies);hashlist_free(&h->extraknown);if (h->metadata)free(h->metadata);hunklistfree(&h->hunks);}
}struct change *changestoreget(struct changestore *store, struct hash *hash){size_t i;for (i = 0; i < store->len; i++) {if (hasheq(hash, &store->entries[i].hash))return &store->entries[i].change;}return NULL;}// loading changes as needed: ==15877== total heap usage: 326 allocs, 326 frees, 50,066,715 bytes allocated/*** load a change by the given hash into the changestore*/intchangestoreload(struct changestore *store, struct hash *hash){struct changeentry *ch;size_t i;int err;if (store->len == store->cap) {/* resize */size_t newcap = store->cap << 1;store->entries = xrealloc(store->entries, sizeof(struct changeentry) * newcap);store->cap = newcap;}i = store->len;ch = &store->entries[i];err = loadchangeh(&ch->change, &ch->hash, store->repodir, hash, 0);if (err)return err;store->len++;return err;}voidchangestoreinit(struct changestore *s, size_t cap, const char *repodir){s->repodir = xstrdup(repodir);s->entries = xmalloc(sizeof(struct changeentry) * cap);s->cap = cap;s->len = 0;}voidchangestorefree(struct changestore *s){size_t i;struct change *c;/* Free all the entries first */for (i = 0; i < s->len; i++) {c = &s->entries[i].change;hashedfree(&c->hashed);if (c->contents)free(c->contents);}free(s->repodir);free(s->entries);}voidauthorsfree(struct authors *authors){size_t i, j;struct author *author;for (i = 0; i < authors->len; i++) {author = &authors->map[i];for (j = 0; j < author->len; j++) {free(author->entries[j].key);free(author->entries[j].value);}free(author->entries);}free(authors->map);
voidhashedfree(struct hashed *h){free(h->header.message);if (h->header.description)free(h->header.description);free(h->header.timestamp);authorsfree(&h->header.authors);hashlist_free(&h->dependencies);hashlist_free(&h->extraknown);if (h->metadata)free(h->metadata);hunklistfree(&h->hunks);}
for (i = 0; i < ch->change.hashed.dependencies.len; i++) {err = loadchangeh(&changestore.entries[x].change,&changestore.entries[x].hash, repodir,&ch->change.hashed.dependencies.entries[i], verbose);if (err)goto changeout;changestore.len++;changestore.entries[x].num = x + 1;x++;}for (i = 0; i < ch->change.hashed.extraknown.len; i++) {err = loadchangeh(&changestore.entries[x].change,&changestore.entries[x].hash, repodir,&ch->change.hashed.extraknown.entries[i], verbose);if (err)goto changeout;changestore.len++;changestore.entries[x].num = x + 1;x++;}