From: Rusty Russell Date: Wed, 30 Nov 2011 02:39:07 +0000 (+1030) Subject: tdb2: display capability information in tdb_summary() X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=b3ca95351517e76b635347b39382b059a66f8388 tdb2: display capability information in tdb_summary() This means we know they're there in future, and what restrictions they carry. --- diff --git a/ccan/tdb2/summary.c b/ccan/tdb2/summary.c index 4a22f2e5..f3a3a085 100644 --- a/ccan/tdb2/summary.c +++ b/ccan/tdb2/summary.c @@ -19,6 +19,34 @@ #include #include +#define SUMMARY_FORMAT \ + "Size of file/data: %zu/%zu\n" \ + "Number of records: %zu\n" \ + "Smallest/average/largest keys: %zu/%zu/%zu\n%s" \ + "Smallest/average/largest data: %zu/%zu/%zu\n%s" \ + "Smallest/average/largest padding: %zu/%zu/%zu\n%s" \ + "Number of free records: %zu\n" \ + "Smallest/average/largest free records: %zu/%zu/%zu\n%s" \ + "Number of uncoalesced records: %zu\n" \ + "Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n%s" \ + "Toplevel hash used: %u of %u\n" \ + "Number of chains: %zu\n" \ + "Number of subhashes: %zu\n" \ + "Smallest/average/largest subhash entries: %zu/%zu/%zu\n%s" \ + "Percentage keys/data/padding/free/rechdrs/freehdrs/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n" + +#define BUCKET_SUMMARY_FORMAT_A \ + "Free bucket %zu: total entries %zu.\n" \ + "Smallest/average/largest length: %zu/%zu/%zu\n%s" +#define BUCKET_SUMMARY_FORMAT_B \ + "Free bucket %zu-%zu: total entries %zu.\n" \ + "Smallest/average/largest length: %zu/%zu/%zu\n%s" +#define CAPABILITY_FORMAT \ + "Capability %llu%s\n" + +#define HISTO_WIDTH 70 +#define HISTO_HEIGHT 20 + static tdb_off_t count_hash(struct tdb_context *tdb, tdb_off_t hash_off, unsigned bits) { @@ -125,37 +153,70 @@ static enum TDB_ERROR summarize(struct tdb_context *tdb, return TDB_SUCCESS; } -#define SUMMARY_FORMAT \ - "Size of file/data: %zu/%zu\n" \ - "Number of records: %zu\n" \ - "Smallest/average/largest keys: %zu/%zu/%zu\n%s" \ - "Smallest/average/largest data: %zu/%zu/%zu\n%s" \ - "Smallest/average/largest padding: %zu/%zu/%zu\n%s" \ - "Number of free records: %zu\n" \ - "Smallest/average/largest free records: %zu/%zu/%zu\n%s" \ - "Number of uncoalesced records: %zu\n" \ - "Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n%s" \ - "Toplevel hash used: %u of %u\n" \ - "Number of chains: %zu\n" \ - "Number of subhashes: %zu\n" \ - "Smallest/average/largest subhash entries: %zu/%zu/%zu\n%s" \ - "Percentage keys/data/padding/free/rechdrs/freehdrs/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n" +static size_t num_capabilities(struct tdb_context *tdb) +{ + tdb_off_t off, next; + const struct tdb_capability *cap; + size_t count = 0; -#define BUCKET_SUMMARY_FORMAT_A \ - "Free bucket %zu: total entries %zu.\n" \ - "Smallest/average/largest length: %zu/%zu/%zu\n%s" -#define BUCKET_SUMMARY_FORMAT_B \ - "Free bucket %zu-%zu: total entries %zu.\n" \ - "Smallest/average/largest length: %zu/%zu/%zu\n%s" + off = tdb_read_off(tdb, offsetof(struct tdb_header, capabilities)); + if (TDB_OFF_IS_ERR(off)) + return count; -#define HISTO_WIDTH 70 -#define HISTO_HEIGHT 20 + /* Count capability list. */ + for (; off; off = next) { + cap = tdb_access_read(tdb, off, sizeof(*cap), true); + if (TDB_PTR_IS_ERR(cap)) { + break; + } + count++; + next = cap->next; + tdb_access_release(tdb, cap); + } + return count; +} + +static void add_capabilities(struct tdb_context *tdb, size_t num, char *summary) +{ + tdb_off_t off, next; + const struct tdb_capability *cap; + size_t count = 0; + + /* Append to summary. */ + summary += strlen(summary); + + off = tdb_read_off(tdb, offsetof(struct tdb_header, capabilities)); + if (TDB_OFF_IS_ERR(off)) + return; + + /* Walk capability list. */ + for (; off; off = next) { + cap = tdb_access_read(tdb, off, sizeof(*cap), true); + if (TDB_PTR_IS_ERR(cap)) { + break; + } + count++; + sprintf(summary, CAPABILITY_FORMAT, + cap->type & TDB_CAP_TYPE_MASK, + /* Noopen? How did we get here? */ + (cap->type & TDB_CAP_NOOPEN) ? " (unopenable)" + : ((cap->type & TDB_CAP_NOWRITE) + && (cap->type & TDB_CAP_NOCHECK)) ? " (uncheckable,read-only)" + : (cap->type & TDB_CAP_NOWRITE) ? " (read-only)" + : (cap->type & TDB_CAP_NOCHECK) ? " (uncheckable)" + : ""); + summary += strlen(summary); + next = cap->next; + tdb_access_release(tdb, cap); + } +} enum TDB_ERROR tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags, char **summary) { tdb_len_t len; + size_t num_caps; struct tally *ftables, *hashes, *freet, *keys, *data, *extra, *uncoal, *chains; char *hashesg, *freeg, *keysg, *datag, *extrag, *uncoalg; @@ -214,6 +275,8 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb, uncoalg = tally_histogram(uncoal, HISTO_WIDTH, HISTO_HEIGHT); } + num_caps = num_capabilities(tdb); + /* 20 is max length of a %llu. */ len = strlen(SUMMARY_FORMAT) + 33*20 + 1 + (hashesg ? strlen(hashesg) : 0) @@ -221,7 +284,8 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb, + (keysg ? strlen(keysg) : 0) + (datag ? strlen(datag) : 0) + (extrag ? strlen(extrag) : 0) - + (uncoalg ? strlen(uncoalg) : 0); + + (uncoalg ? strlen(uncoalg) : 0) + + num_caps * (strlen(CAPABILITY_FORMAT) + 20*4); *summary = malloc(len); if (!*summary) { @@ -268,6 +332,8 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb, + sizeof(struct tdb_chain) * tally_num(chains)) * 100.0 / tdb->file->map_size); + add_capabilities(tdb, num_caps, *summary); + unlock: free(hashesg); free(freeg); diff --git a/ccan/tdb2/test/run-capabilities.c b/ccan/tdb2/test/run-capabilities.c index e3026561..4b25f9c5 100644 --- a/ccan/tdb2/test/run-capabilities.c +++ b/ccan/tdb2/test/run-capabilities.c @@ -79,11 +79,12 @@ static void create_tdb(const char *name, int main(int argc, char *argv[]) { struct tdb_context *tdb; + char *summary; failtest_init(argc, argv); failtest_hook = block_repeat_failures; failtest_exit_check = exit_check_log; - plan_tests(35); + plan_tests(60); failtest_suppress = true; /* Capability says you can ignore it? */ @@ -114,6 +115,9 @@ int main(int argc, char *argv[]) ok1(tap_log_messages == 0); ok1(tdb_check(tdb, NULL, NULL) == TDB_SUCCESS); ok1(tap_log_messages == 0); + ok1(tdb_summary(tdb, 0, &summary) == TDB_SUCCESS); + ok1(strstr(summary, "Capability 1\n")); + free(summary); tdb_close(tdb); /* Capability says you can't check. */ @@ -133,6 +137,10 @@ int main(int argc, char *argv[]) /* We expect a warning! */ ok1(tap_log_messages == 1); ok1(strstr(log_last, "capabilit")); + ok1(tdb_summary(tdb, 0, &summary) == TDB_SUCCESS); + ok1(strstr(summary, "Capability 1\n")); + ok1(strstr(summary, "Capability 2 (uncheckable)\n")); + free(summary); tdb_close(tdb); /* Capability says you can't write. */ @@ -162,6 +170,10 @@ int main(int argc, char *argv[]) ok1(tap_log_messages == 2); ok1(tdb_check(tdb, NULL, NULL) == TDB_SUCCESS); ok1(tap_log_messages == 2); + ok1(tdb_summary(tdb, 0, &summary) == TDB_SUCCESS); + ok1(strstr(summary, "Capability 1\n")); + ok1(strstr(summary, "Capability 2 (read-only)\n")); + free(summary); tdb_close(tdb); /* Capability says you can't open. */ @@ -211,6 +223,48 @@ int main(int argc, char *argv[]) /* We expect a warning! */ ok1(tap_log_messages == 5); ok1(strstr(log_last, "unknown")); + ok1(tdb_summary(tdb, 0, &summary) == TDB_SUCCESS); + ok1(strstr(summary, "Capability 1\n")); + ok1(strstr(summary, "Capability 2 (uncheckable)\n")); + ok1(strstr(summary, "Capability 3 (read-only)\n")); + free(summary); + tdb_close(tdb); + + /* Two capability flags in one. */ + create_tdb("run-capabilities.tdb", + 1, false, false, false, + 2, true, true, false, + 0); + + failtest_suppress = false; + tdb = tdb_open("run-capabilities.tdb", TDB_DEFAULT, O_RDWR, 0, + &tap_log_attr); + failtest_suppress = true; + /* We expect a message. */ + ok1(!tdb); + if (!ok1(tap_log_messages == 6)) + goto out; + if (!ok1(strstr(log_last, "unknown"))) + goto out; + ok1(strstr(log_last, "write")); + + /* We can open it read-only though! */ + failtest_suppress = false; + tdb = tdb_open("run-capabilities.tdb", TDB_DEFAULT, O_RDONLY, 0, + &tap_log_attr); + failtest_suppress = true; + if (!ok1(tdb)) + goto out; + ok1(tap_log_messages == 6); + ok1(tdb_get_flags(tdb) & TDB_CANT_CHECK); + ok1(tdb_check(tdb, NULL, NULL) == TDB_SUCCESS); + /* We expect a warning! */ + ok1(tap_log_messages == 7); + ok1(strstr(log_last, "unknown")); + ok1(tdb_summary(tdb, 0, &summary) == TDB_SUCCESS); + ok1(strstr(summary, "Capability 1\n")); + ok1(strstr(summary, "Capability 2 (uncheckable,read-only)\n")); + free(summary); tdb_close(tdb); out: