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 |