diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/jio.c | 12 | ||||
| -rw-r--r-- | src/report-layout.c | 178 | ||||
| -rw-r--r-- | src/report-layout.h | 8 | 
4 files changed, 198 insertions, 2 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index cfc2f3f..0ea6ebd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ jio_SOURCES = \  	readfile.h \  	reclaim-tail-waste.c \  	reclaim-tail-waste.h \ +	report-layout.c \ +	report-layout.h \  	report-tail-waste.c \  	report-tail-waste.h \  	report-usage.c \ @@ -20,6 +20,7 @@  #include <iou.h>  #include "reclaim-tail-waste.h" +#include "report-layout.h"  #include "report-tail-waste.h"  #include "report-usage.h" @@ -55,6 +56,7 @@ int main(int argc, char *argv[])  			"         tail-waste  reclaim wasted space from tails of archives\n"  			"\n"  			" report  [subcmd]    report statistics about journal files\n" +			"         layout      report layout of objects, writes a .layout file per journal\n"  			"         usage       report space used by various object types\n"  			"         tail-waste  report extra space allocated onto tails\n"  			" version             print jio version\n" @@ -98,11 +100,17 @@ int main(int argc, char *argv[])  		}  	} else if (!strcmp(argv[1], "report")) {  		if (argc < 3) { -			printf("Usage: %s report {usage,tail-waste}\n", argv[0]); +			printf("Usage: %s report {layout,usage,tail-waste}\n", argv[0]);  			return 0;  		} -		if (!strcmp(argv[2], "tail-waste")) { +		if (!strcmp(argv[2], "layout")) { +			r = jio_report_layout(iou, argc, argv); +			if (r < 0) { +				fprintf(stderr, "failed to report layout: %s\n", strerror(-r)); +				return 1; +			} +		} else if (!strcmp(argv[2], "tail-waste")) {  			r = jio_report_tail_waste(iou, argc, argv);  			if (r < 0) {  				fprintf(stderr, "failed to report tail waste: %s\n", strerror(-r)); diff --git a/src/report-layout.c b/src/report-layout.c new file mode 100644 index 0000000..e8d686e --- /dev/null +++ b/src/report-layout.c @@ -0,0 +1,178 @@ +/* + *  Copyright (C) 2020 - Vito Caputo - <vcaputo@pengaru.com> + * + *  This program is free software: you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 3 as published + *  by the Free Software Foundation. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> + +#include <iou.h> +#include <thunk.h> + +#include "bootid.h" +#include "humane.h" +#include "journals.h" +#include "machid.h" +#include "report-layout.h" + +#include "upstream/journal-def.h" + + +static const char type_map[_OBJECT_TYPE_MAX] = { +	[OBJECT_UNUSED] = '?', +	[OBJECT_DATA] = 'd', +	[OBJECT_FIELD] = 'f', +	[OBJECT_ENTRY] = 'e', +	[OBJECT_DATA_HASH_TABLE] = 'D', +	[OBJECT_FIELD_HASH_TABLE] = 'F', +	[OBJECT_ENTRY_ARRAY] = 'A', +	[OBJECT_TAG] = 'T', +}; + +/* TODO: this should be either argv settable or just determined at runtime */ +#define PAGE_SIZE 4096 + +THUNK_DEFINE_STATIC(per_data_object, uint64_t *, iter_offset, ObjectHeader *, iter_object_header, FILE *, out) +{ +	char		boundary_marker[22] = ""; +	char		alignment_marker[3] = ""; +	uint64_t	off, this_page, next_page, page_delta, aligned_delta; + +	assert(iter_offset); +	assert(iter_object_header); +	assert(out); + +	off = *iter_offset; + +	if (!off) { +		fprintf(out, "\n"); +		fflush(out); +		fclose(out); +		return 0; +	} + + +	this_page = off & ~(PAGE_SIZE-1); +	next_page = (off + iter_object_header->size + PAGE_SIZE-1) & ~(PAGE_SIZE-1); +	page_delta = next_page - this_page; + +	if (page_delta > PAGE_SIZE * 2) +		snprintf(boundary_marker, sizeof(boundary_marker), "|%"PRIu64"|", page_delta / PAGE_SIZE - 1); +	else if (page_delta > PAGE_SIZE) +		snprintf(boundary_marker, sizeof(boundary_marker), "|"); + +	aligned_delta = ALIGN64(iter_object_header->size) - iter_object_header->size; + +	if (aligned_delta > 1) +		snprintf(alignment_marker, sizeof(alignment_marker), "+%"PRIu64, aligned_delta); +	else if (aligned_delta) +		snprintf(alignment_marker, sizeof(alignment_marker), "+"); + +	fprintf(out, "%s%c%s%"PRIu64"%s ", +		this_page == off ? "| " : "", +		type_map[iter_object_header->type], +		boundary_marker, +		iter_object_header->size, +		alignment_marker); + +	return 0; +} + + +THUNK_DEFINE_STATIC(per_journal, iou_t *, iou, journal_t **, journal_iter) +{ +	struct { +		journal_t	*journal; +		Header		header; +		uint64_t	iter_offset; +		ObjectHeader	iter_object_header; +		FILE		*out; +	} *foo; + +	thunk_t		*closure; +	char		*fname; +	FILE		*f; + +	assert(iou); +	assert(journal_iter); + +	fname = malloc(strlen((*journal_iter)->name) + sizeof(".layout")); +	if (!fname) +		return -ENOMEM; + +	sprintf(fname, "%s.layout", (*journal_iter)->name); +	f = fopen(fname, "w+"); +	free(fname); +	if (!f) +		return -errno; + +	fprintf(f, "Layout for \"%s\"\n", (*journal_iter)->name); +	fprintf(f, +		"Legend:\n" +		"%c     OBJECT_UNUSED\n" +		"%c     OBJECT_DATA\n" +		"%c     OBJECT_FIELD\n" +		"%c     OBJECT_ENTRY\n" +		"%c     OBJECT_DATA_HASH_TABLE\n" +		"%c     OBJECT_FIELD_HASH_TABLE\n" +		"%c     OBJECT_ENTRY_ARRAY\n" +		"%c     OBJECT_TAG\n\n" +		"|N|    object spans N page boundaries (page size used=%u)\n" +		"|      single page boundary\n" +		"+N     N bytes of alignment padding\n" +		"+      single byte alignment padding\n\n", + +		type_map[OBJECT_UNUSED], +		type_map[OBJECT_DATA], +		type_map[OBJECT_FIELD], +		type_map[OBJECT_ENTRY], +		type_map[OBJECT_DATA_HASH_TABLE], +		type_map[OBJECT_FIELD_HASH_TABLE], +		type_map[OBJECT_ENTRY_ARRAY], +		type_map[OBJECT_TAG], +		PAGE_SIZE); + +	closure = THUNK_ALLOC(per_data_object, (void **)&foo, sizeof(*foo)); +	foo->journal = *journal_iter; +	foo->out = f; + +	return journal_get_header(iou, &foo->journal, &foo->header, THUNK( +			journal_iter_objects(iou, &foo->journal, &foo->header, &foo->iter_offset, &foo->iter_object_header, THUNK_INIT( +				per_data_object(closure, &foo->iter_offset, &foo->iter_object_header, foo->out))))); +} + + +/* print the layout of contents per journal */ +int jio_report_layout(iou_t *iou, int argc, char *argv[]) +{ +	char		*machid; +	journals_t	*journals; +	journal_t	*journal_iter; +	int		r; + +	r = machid_get(iou, &machid, THUNK( +		journals_open(iou, &machid, O_RDONLY, &journals, THUNK( +			journals_for_each(&journals, &journal_iter, THUNK( +				per_journal(iou, &journal_iter))))))); +	if (r < 0) +		return r; + +	r = iou_run(iou); +	if (r < 0) +		return r; + +	return 0; +} diff --git a/src/report-layout.h b/src/report-layout.h new file mode 100644 index 0000000..bd82122 --- /dev/null +++ b/src/report-layout.h @@ -0,0 +1,8 @@ +#ifndef _JIO_REPORT_LAYOUT +#define _JIO_REPORT_LAYOUT + +typedef struct iou_t iou_t; + +int jio_report_layout(iou_t *iou, int argc, char *argv[]); + +#endif | 
