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.
HMFIDMVZCIROCMAWQWVWWUULOW3ZHKMLRMOPAE4QUDLVR437O2OAC
EHVLRMEF6YK5FRIV5V7V6P5RHJPCYKMSW5OVKDXLUEWHEM624FBAC
RRYWNHFE3EIRQYBGMSZRLDGKWHVMDAO42QNKFQ2KVYPDC4IHANTAC
PC54CREYZ6MOAPTPUUFV5VD3FMRTT6FGOUMOO25GD6BFZJMSS6BAC
CWII6DASI3JOJAA4PXSSVJOEUBT32KTGB3VZXKTUCFXK3KNRH2DAC
UM5XFLGIZYSFAP6TFEZR4APDSSHRHZJDQKXPFGKT6LUAK7QXN33QC
5D2IYPL75HEP6JUEILEADSZRRSV72NECT6UQR3PORNDR35I2P5GQC
Q7TKZCJP2Z75EICZYKCEZDHKGERSOKZGMTSU3UXETBHTF663T66AC
Y26WT3ZFN7KSVXOZ26B5Y2OR4M4VQYQLPMAHPC4O5VIT3ENBISXAC
YFBKBUKBX3JB7OCB4D3ZKSLWTP6QWZ36HEE5GZROJE55RK33MZCAC
LVX6U4EKYXM6H32X5SZS4UBIM5PW4ND4F4QQOF5EQDX3DUHBYFGAC
XTVLIC243WZF52NVTNRA3SV3WLE2ZZ5GTFQOK45IOLMXYQMTLOSAC
LPGHALLKCQRJUB7BNHABAG2VEEAFTUSN3WAPASM5B3V6JJ54GXJQC
7WA2F6RSQBGJJE5MZGQGAYJOWYEKQUWVI2MTZ4AMICEEQFENXANQC
YDQLW2ZOAH7PZ7HHVTSFUO5IWE6O7FDNXVNIN7GG4TJ3P2B2BM4AC
res = changecontents(changes, a, contents, &n);
// valgrind --leak-check=full build/ani change YM2LC6QP2D7TK3JUKOXWUWTQEGMCEGQDGPTOZPWC3BRDFNRKSZWQC # this one has file additions
// our current scheme allocates more than 140 MB!! See about bringing that down
// the "scratch pad" idea only takes out about four allocations here...
// ==14997== total heap usage: 1,204 allocs, 1,204 frees, 149,446,210 bytes allocated
res = changecontents(changes, a, contents, repodir, &n);
}
}
}
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;
}
void
changestoreinit(struct changestore *s, size_t cap)
{
s->entries = xmalloc(sizeof(struct changeentry) * cap);
s->cap = cap;
s->len = 0;
}
void
changestorefree(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);
}
void
authorsfree(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(authors->map);
}
void
hashedfree(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
*/
int
changestoreload(
struct changestore *store, struct hash *hash, const char *repodir
)
{
struct changeentry *ch;
size_t i;
int err;
if (store->len == store->cap) {
printf("resizing... len = %lu cap = %lu\n", store->len,
store->cap);
/* resize */
size_t newcap = store->cap << 1;
store->entries = xrealloc(
store->entries, sizeof(struct changeentry) * newcap
);
store->cap = newcap;
}
printf("len = %lu cap = %lu\n", store->len, store->cap);
i = store->len;
ch = &store->entries[i];
err = loadchangeh(&ch->change, &ch->hash, repodir, hash, 0);
if (err)
return err;
store->len++;
return err;
}
void
changestoreinit(struct changestore *s, size_t cap)
{
s->entries = xmalloc(sizeof(struct changeentry) * cap);
s->cap = cap;
s->len = 0;
}
void
changestorefree(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);
void
authorsfree(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);
}
void
hashedfree(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);
}