示例#1
0
/**
 * Iterate on each item of the map, applying callback.
 */
void
map_foreach(const map_t *m, keyval_fn_t cb, void *u)
{
	map_check(m);
	g_assert(cb);

	switch (m->type) {
	case MAP_HASH:
		htable_foreach(m->u.ht, (ckeyval_fn_t) cb, u);
		break;
	case MAP_ORDERED_HASH:
		ohash_table_foreach(m->u.ot, cb, u);
		break;
	case MAP_PATRICIA:
		{
			struct pat_foreach ctx;

			ctx.cb = cb;
			ctx.u = u;

			patricia_foreach(m->u.pt, pat_foreach_wrapper, &ctx);
		}
		break;
	case MAP_MAXTYPE:
		g_assert_not_reached();
	}
}
示例#2
0
/**
 * ccache_free(cache):
 * Free the cache and all of its entries.
 */
void
ccache_free(CCACHE * cache)
{
	struct ccache_internal * C = cache;

	if (cache == NULL)
		return;

	/* Free all of the records in the patricia tree. */
	patricia_foreach(C->tree, callback_free, NULL);

	/* Free the patricia tree itself. */
	patricia_free(C->tree);

	/* Unmap memory. */
#ifdef HAVE_MMAP
	if (C->datalen > 0 && munmap(C->data, C->datalen))
		warnp("munmap failed on cache data");
#else
	free(C->data);
#endif

	/* Free the cache. */
	free(C);
}
示例#3
0
/**
 * ccache_read(path):
 * Read the chunkification cache (if present) from the directory ${path};
 * return a Patricia tree mapping absolute paths to cache entries.
 */
CCACHE *
ccache_read(const char * path)
{
	struct ccache_internal * C;
	struct ccache_read_internal R;
	struct ccache_record * ccr;
#ifdef HAVE_MMAP
	struct stat sb;
	off_t fpos;
	long int pagesize;
#endif
	size_t i;
	uint8_t N[4];

	/* The caller must pass a file name to be read. */
	assert(path != NULL);

	/* Allocate memory for the cache. */
	if ((C = malloc(sizeof(struct ccache_internal))) == NULL)
		goto err0;
	memset(C, 0, sizeof(struct ccache_internal));

	/* Create a Patricia tree to store cache entries. */
	if ((C->tree = patricia_init()) == NULL)
		goto err1;

	/* Construct the name of cache file. */
	if (asprintf(&R.s, "%s/cache", path) == -1) {
		warnp("asprintf");
		goto err2;
	}

	/* Open the cache file. */
	if ((R.f = fopen(R.s, "r")) == NULL) {
		/* ENOENT isn't an error. */
		if (errno != ENOENT) {
			warnp("fopen(%s)", R.s);
			goto err3;
		}

		/* No cache exists on disk; return an empty cache. */
		goto emptycache;
	}

	/**
	 * We read the cache file in three steps:
	 * 1. Read a little-endian uint32_t which indicates the number of
	 *    records in the cache file.
	 * 2. Read N (record, path suffix) pairs and insert them into a
	 *    Patricia tree.
	 * 3. Iterate through the tree and read chunk headers and compressed
	 *    entry trailers.
	 */

	/* Read the number of cache entries. */
	if (fread(N, 4, 1, R.f) != 1) {
		if (ferror(R.f))
			warnp("Error reading cache: %s", R.s);
		else
			warn0("Error reading cache: %s", R.s);
		goto err4;
	}
	R.N = le32dec(N);

	/* Read N (record, path suffix) pairs. */
	R.sbuf = NULL;
	R.sbuflen = R.slen = R.datalen = 0;
	for (i = 0; i < R.N; i++) {
		if ((ccr = read_rec(&R)) == NULL)
			goto err5;
		if (patricia_insert(C->tree, R.sbuf, R.slen, ccr))
			goto err5;
		C->chunksusage += ccr->nch * sizeof(struct chunkheader);
		C->trailerusage += ccr->tzlen;
	}

#ifdef HAVE_MMAP
	/* Obtain page size, since mmapped regions must be page-aligned. */
	if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) {
		warnp("sysconf(_SC_PAGESIZE)");
		goto err5;
	}

	/* Map the remainder of the cache into memory. */
	fpos = ftello(R.f);
	if (fpos == -1) {
		warnp("ftello(%s)", R.s);
		goto err5;
	}
	if (fstat(fileno(R.f), &sb)) {
		warnp("fstat(%s)", R.s);
		goto err5;
	}
	if (sb.st_size != (off_t)(fpos + R.datalen)) {
		warn0("Cache has incorrect size (%jd, expected %jd)\n",
		    (intmax_t)(sb.st_size), (intmax_t)(fpos + R.datalen));
		goto err5;
	}
	C->datalen = R.datalen + (fpos % pagesize);
	if ((C->data = mmap(NULL, C->datalen, PROT_READ,
#ifdef MAP_NOCORE
	    MAP_PRIVATE | MAP_NOCORE,
#else
	    MAP_PRIVATE,
#endif
	    fileno(R.f), fpos - (fpos % pagesize))) == MAP_FAILED) {
		warnp("mmap(%s)", R.s);
		goto err5;
	}
	R.data = (uint8_t *)C->data + (fpos % pagesize);
#else
	/* Allocate space. */
	C->datalen = R.datalen;
	if (((C->data = malloc(C->datalen)) == NULL) && (C->datalen > 0))
		goto err5;
	if (fread(C->data, C->datalen, 1, R.f) != 1) {
		warnp("fread(%s)", R.s);
		goto err6;
	}
	R.data = (uint8_t *)C->data;
#endif

	/* Iterate through the tree reading chunk headers and trailers. */
	if (patricia_foreach(C->tree, callback_read_data, &R)) {
		warnp("Error reading cache: %s", R.s);
		goto err6;
	}

	/* Free buffer used for storing paths. */
	free(R.sbuf);

	/* Close the cache file. */
	fclose(R.f);

	/* Free string allocated by asprintf. */
	free(R.s);

	/* Success! */
	return (C);

emptycache:
	/* Nothing went wrong, but there's nothing on disk. */
	free(R.s);
	return (C);

err6:
#ifdef HAVE_MMAP
	if (C->datalen > 0)
		munmap(C->data, C->datalen);
#else
	free(C->data);
#endif
err5:
	free(R.sbuf);
	patricia_foreach(C->tree, callback_free, NULL);
err4:
	fclose(R.f);
err3:
	free(R.s);
err2:
	patricia_free(C->tree);
err1:
	free(C);
err0:
	/* Failure! */
	return (NULL);
}
示例#4
0
/**
 * ccache_write(cache, path):
 * Write the given chunkification cache into the directory ${path}.
 */
int
ccache_write(CCACHE * cache, const char * path)
{
	struct ccache_internal * C = cache;
	struct ccache_write_internal W;
	uint8_t N[4];
	char * s_old;

	/* Construct name of temporary cache file. */
	if (asprintf(&W.s, "%s/cache.new", path) == -1) {
		warnp("asprintf");
		goto err0;
	}

	/* Open the cache file for writing. */
	if ((W.f = fopen(W.s, "w")) == NULL) {
		warnp("fopen(%s)", W.s);
		goto err1;
	}

	/**
	 * We make three passes through the cache tree:
	 * 1. Counting the number of records which will be written to disk.
	 *    This is necessary since records in the cache which are too old
	 *    will not be written, but the on-disk cache format starts with
	 *    the number of records.
	 * 2. Writing the records and suffixes.
	 * 3. Writing the cached chunk headers and compressed entry trailers.
	 */

	/* Count the number of records which need to be written. */
	W.N = 0;
	if (patricia_foreach(C->tree, callback_count, &W)) {
		warnp("patricia_foreach");
		goto err2;
	};

	/* Write the number of records to the file. */
	le32enc(N, W.N);
	if (fwrite(N, 4, 1, W.f) != 1) {
		warnp("fwrite(%s)", W.s);
		goto err2;
	}

	/* Write the records and suffixes. */
	W.sbuf = NULL;
	W.sbuflen = 0;
	if (patricia_foreach(C->tree, callback_write_rec, &W)) {
		warnp("Error writing cache to %s", W.s);
		goto err2;
	}
	free(W.sbuf);

	/* Write the chunk headers and compressed entry trailers. */
	if (patricia_foreach(C->tree, callback_write_data, &W)) {
		warnp("Error writing cache to %s", W.s);
		goto err2;
	}

	/* Close the file. */
	fclose(W.f);

	/* Construct the name of the old cache file. */
	if (asprintf(&s_old, "%s/cache", path) == -1) {
		warnp("asprintf");
		goto err1;
	}

	/* Delete the old file, if it exists. */
	if (unlink(s_old)) {
		if (errno != ENOENT) {
			warnp("unlink(%s)", s_old);
			free(s_old);
			goto err1;
		}
	}
	/* Move the new cache file into place. */
	if (rename(W.s, s_old)) {
		warnp("rename(%s, %s)", W.s, s_old);
		free(s_old);
		goto err1;
	}

	/* Free strings allocated by asprintf. */
	free(s_old);
	free(W.s);

	/* Success! */
	return (0);

err2:
	fclose(W.f);
err1:
	free(W.s);
err0:
	/* Failure! */
	return (-1);
}