rc_t KeyRingDatabaseSave ( struct KeyRingData* self, struct KDirectory* wd, const char* path ) { rc_t rc; VDBManager* vdbMgr; rc = VDBManagerMakeUpdate( &vdbMgr, wd ); if (rc == 0) { VSchema* schema; rc = VDBManagerMakeSchema(vdbMgr, &schema); if (rc == 0) { rc = VSchemaParseText ( schema, "keyring_schema", schema_text, string_measure(schema_text, NULL) ); if (rc == 0) { /* create a database */ VDatabase* db; rc = VDBManagerCreateDB(vdbMgr, & db, schema, "keyring:KEYRING", kcmCreate | kcmMD5, path); if (rc == 0) { rc_t rc2; rc = SaveProjects(&self->projects, db); if (rc == 0) rc = SaveObjects(&self->objects, db); /*TODO: SaveKeys */ rc2 = VDatabaseRelease(db); if (rc == 0) rc = rc2; } } VSchemaRelease(schema); } VDBManagerRelease(vdbMgr); } return rc; }
static rc_t static_write(void) { const char *schema_text = "version 1; include 'vdb/vdb.vschema'; table foo #1 { column ascii bar { read = .bar; } physical ascii .bar = bar; }"; bool force = 1; rc_t rc; VDBManager *vmgr; rc = VDBManagerMakeUpdate ( & vmgr, NULL ); if ( rc != 0 ) LOGERR ( klogInt, rc, "failed to make VDB manager" ); else { VSchema *schema; rc = VDBManagerMakeSchema ( vmgr, & schema ); if ( rc != 0 ) LOGERR ( klogInt, rc, "failed to make empty schema" ); else { rc = VSchemaParseText( schema, "static_schema", schema_text, strlen(schema_text) ); if ( rc != 0 ) PLOGERR ( klogErr, (klogErr, rc, "failed to parse schema '$(text)'", "test=%s", schema_text )); else { VTable *vtbl; rc = VDBManagerCreateTable ( vmgr, & vtbl, schema, "foo", force ? kcmInit : kcmCreate, table_path ); if ( rc != 0 ) { PLOGERR ( klogErr, (klogErr, rc, "failed to $(cmode) table '$(path)'" , "cmode=%s,path=%s" , force ? "create or replace" : "create" , table_path )); } else { VCursor *curs; rc = VTableCreateCursorWrite ( vtbl, & curs, kcmInsert ); if ( rc != 0 ) LOGERR ( klogInt, rc, "failed to create cursor" ); else { uint32_t idx; rc = VCursorAddColumn ( curs, &idx, "bar" ); if ( rc != 0 ) { PLOGERR ( klogErr, (klogErr, rc, "failed to add column '$(col)' to cursor" , "col=bar" )); } else { rc = VCursorOpen ( curs ); if ( rc != 0 ) LOGERR ( klogErr, rc, "failed to open cursor" ); else { int i; for ( i = 0; i != 10 && rc == 0; ++i ) { rc = VCursorOpenRow ( curs ); if ( rc != 0 ) LOGERR ( klogErr, rc, "failed to open cursor row" ); else { rc_t rc2; uint32_t count = sizeof(buff) - 1; rc = VCursorWrite ( curs, idx, 8, buff, 0, count ); if ( rc != 0 ) { int64_t rid = 0; VCursorRowId ( curs, & rid ); PLOGERR ( klogInt, (klogInt, rc, "failed to write data to row $(row_id)'" , "row_id=%ld" , rid )); break; } if ( rc == 0 ) { rc = VCursorCommitRow ( curs ); if ( rc != 0 ) LOGERR ( klogErr, rc, "failed to commit row" ); } rc2 = VCursorCloseRow ( curs ); if ( rc2 != 0 ) { LOGERR ( klogErr, rc2, "failed to close cursor row" ); if ( rc == 0 ) rc = rc2; } } } if ( GetRCState ( rc ) == rcDone ) rc = 0; if ( rc == 0 ) rc = VCursorCommit ( curs ); } } VCursorRelease ( curs ); } #if 1 if ( rc == 0 ) rc = VTableReindex ( vtbl ); #endif VTableRelease ( vtbl ); } } VSchemaRelease ( schema ); } VDBManagerRelease ( vmgr ); } return rc; }
rc_t run (const char * table_path, uint64_t N ) { static const char *colInf[] = { "C1: Same value, same length", "C2: Var. value, same length", "C3: Var. value, var. legnth", "C4: Same value except I row", "C5: Same value except L row" }; rc_t rc; uint64_t row = 0; VDBManager *mgr = NULL; VSchema *schema = NULL; VTable *table = NULL; VCursor *cursor; uint32_t idx[COLUMNS]; uint64_t total[COLUMNS]; int i = 0, j = 0, prev = 0; char *buffer[BUFFERS]; /* Initialize arrays */ memset(&idx, 0, sizeof idx); memset(&total, 0, sizeof total); for (i = 0; i < BUFFERS; ++i) { char c; size_t sz = ROWLEN + 1; if (i == (BUFFERS - 1)) sz += ROWLEN; buffer[i] = malloc(sz); for (j = 0, c = 0; j < sz - 1; ++j, ++c) { if (c >= ROWLEN) c -= ROWLEN; buffer[i][j] = '0' + c; } buffer[i][j] = '\0'; } /* Create manager */ rc = VDBManagerMakeUpdate(&mgr, NULL); if (rc != 0) { LOGERR(klogInt, rc, "failed to open vdb library"); } /* Initialize schema */ if (rc == 0) { rc = VDBManagerMakeSchema(mgr, &schema); if (rc != 0) LOGERR(klogInt, rc, "failed to create empty schema"); } if (rc == 0) { char text[512] = "table Table #1 {\n"; char col [128]; for (i = 1; i <= COLUMNS; ++i) { sprintf(col, " column ascii C%d = .C%d; physical ascii .C%d = C%d;\n", i, i, i, i); strcat(text, col); } strcat(text, "};"); STSMSG(1,("Parsing schema:\n%s", text)); rc = VSchemaParseText(schema, "Schema", text, strlen(text)); if (rc != 0) LOGERR(klogInt, rc, "failed to parse schema"); } /* Create table */ if (rc == 0) { STSMSG(1,("Creating %s", tablePath)); rc = VDBManagerCreateTable(mgr, &table, schema, "Table", kcmInit, tablePath); if (rc != 0) LOGERR(klogInt, rc, "failed to create table"); } /* Initialize cursor */ if (rc == 0) { rc = VTableCreateCursorWrite(table, &cursor, kcmInsert); if (rc != 0) LOGERR(klogInt, rc, "failed to create cursor"); } for (i = 0; rc == 0 && i < COLUMNS; ++i) { char col[3]; sprintf(col, "C%d", i + 1); STSMSG(2,("Adding column %s to cursor", col)); rc = VCursorAddColumn(cursor, &idx[i], col); if (rc != 0) PLOGERR(klogInt, (klogInt, rc, "failed to add $(c) to cursor", "c=%s", col)); } if (rc == 0) { rc = VCursorOpen(cursor); if (rc != 0) LOGERR(klogInt, rc, "failed to open cursor"); } /* Write data */ for (row = 0; row < N && rc == 0; ++row) { int max = 2 * ROWLEN - 1; int sz = 0; if ((row % 2) == 0) { int min = 1; sz = min + (int) (max * (rand() / (RAND_MAX + 1.0))); prev = sz; buffer[1][0] = '1'; } else { sz = max + 1 - prev; buffer[1][0] = '2'; } rc = Quitting(); if (rc == 0) { KStsLevel lvl = 2; if (row > 0 && ((row % ROWS) == 0)) { lvl = 1; } STSMSG (lvl, ("Writing row %ji / %ji", row + 1, N)); rc = VCursorOpenRow(cursor); if (rc != 0) LOGERR(klogInt, rc, "failed to open row"); } for (j = 0; j < COLUMNS && rc == 0; ++j) { uint32_t count = 0; int buf = j; switch (j) { case 0: case 1: count = strlen(buffer[j]); break; case 2: count = sz; break; case 3: buf = 0; if (row == 0) buf = 1; count = strlen(buffer[buf]); break; case 4: buf = 0; if (row == (N - 1)) buf = 1; count = strlen(buffer[buf]); break; default: assert(0); break; } STSMSG (3, ("Row %ji/Col.%d: %sd %.*s\n", row + 1, j + 1, count, count, buffer[buf])); rc = VCursorWrite (cursor, idx[j], 8, buffer[buf], 0, count); if (rc != 0) PLOGERR(klogInt, (klogInt, rc, "failed to write row[$i]", "i=%d", j + 1)); total[j] += count; } if (rc == 0) { rc = VCursorCommitRow(cursor); if (rc != 0) LOGERR(klogInt, rc, "failed to commit row"); } if (rc == 0) { rc = VCursorCloseRow(cursor); if (rc != 0) LOGERR(klogInt, rc, "failed to close row"); } } if (rc == 0) { STSMSG (1, ("Commiting cursor\n")); rc = VCursorCommit(cursor); if (rc != 0) LOGERR(klogInt, rc, "failed to commit cursor"); } /* Cleanup */ VCursorRelease(cursor); VTableRelease(table); VSchemaRelease(schema); VDBManagerRelease(mgr); for (i = 0; i < BUFFERS; ++i) { free(buffer[i]); } /* Log */ if (rc == 0) { PLOGMSG(klogInfo, (klogInfo, "$(t)", "t=%s", tablePath)); PLOGMSG(klogInfo,(klogInfo, "$(n)($(N)) rows written - $(b) bytes per row", PLOG_I64(n) "," PLOG_X64(N) ",b=%d", N, N, ROWLEN)); for (i = 0; i < COLUMNS; ++i) { PLOGMSG(klogInfo,(klogInfo, "$(i): $(n)($(N)) bytes", "i=%s," PLOG_I64(n) "," PLOG_X64(N), colInf[i], total[i], total[i])); } } if (rc == 0) { KDirectory *dir = NULL; uint64_t sizes[COLUMNS]; memset(&sizes, 0, sizeof sizes); rc = KDirectoryNativeDir(&dir); if (rc != 0) LOGERR(klogInt, rc, "failed to KDirectoryNativeDir"); else { for (i = 1; i <= COLUMNS; ++i) { uint64_t size = 0; #define FORMAT "%s/col/%s/data" #define KFORMAT "$(d)/col/$(n)/data", "d=%s,n=%s" #define STATUS(action) (action FORMAT, tablePath, name) char name[3]; sprintf(name, "C%d", i); STSMSG (1, STATUS("checking ")); rc = KDirectoryFileSize(dir, &size, FORMAT, tablePath, name); if (rc != 0) { if (GetRCState(rc) == rcNotFound) { STSMSG (2, STATUS("not found ")); rc = 0; } else PLOGERR(klogInt, (klogInt, rc, "failed to check " KFORMAT, tablePath, name)); } else { STSMSG (2, STATUS("found ")); } PLOGMSG(klogInfo, (klogInfo, "Size of $(d)/col/$(n)/data = $(s)", "d=%s,n=%s," PLOG_I64(s), tablePath, name, size)); sizes[i - 1] = size; } } KDirectoryRelease(dir); if (rc == 0) { puts(""); KOutMsg("%ld rows, %d bytes per row:\n", N, ROWLEN); for (i = 0; i < COLUMNS; ++i) { puts(colInf[i]); } puts(""); for (i = 0; i < COLUMNS; ++i) { int64_t over = sizes[i] - total[i]; KOutMsg("C%d: %9ld bytes written; " "%9ld in 'data'", i + 1, total[i], sizes[i]); if (over > 0) { double p = 100.0 * over / sizes[i]; printf(": %7ld extra bytes (%.4f%%)\n", over, p); } else { puts(""); } } } } return rc; }
rc_t run_tests (void) { VDBManager * mgr; rc_t rc; if (verbose) printf("%s call VDBManagerMakeUpdate\n", __func__); rc = VDBManagerMakeUpdate (&mgr, NULL); if (rc) { LOGERR (klogInt, rc, "Failed to open VDBManager"); return rc; } else { VSchema * schema; if (verbose) printf("%s call VDBManagerMakeSchema\n", __func__); rc = VDBManagerMakeSchema (mgr, &schema); printf("%s schema == %p\n", __func__, (void*)schema); if (rc) LOGERR (klogInt, rc, "Failed to make empty schema"); else { if(verbose) printf("%s call VSchemaParseText\n", __func__); rc = VSchemaParseText (schema, "rowlen_schema", schema_text, string_size (schema_text)); if (rc) LOGERR (klogInt, rc, "Failed to parse internal schema"); else { int ix; for ( ix = 0; ix < 6; ++ix) { VTable * table; rc_t orc; if (verbose) printf("%s call open_table\n", __func__); rc = open_table (mgr, schema, &table); if (rc) { LOGERR (klogErr, rc, "Failed to open table"); break; } if (verbose) printf("%s call run_test\n", __func__); rc = run_test (table, &tests[ix]); if (rc) { pLOGERR (klogErr, rc, "Failed $(D)", PLOG_S(D), tests[ix].test_name); } if (verbose) printf("%s call VTableRelease\n", __func__); orc = VTableRelease (table); if (orc) { LOGERR (klogErr, rc, "failed to close table"); } if (orc && (rc == 0)) rc = orc; if (rc) break; } } if (verbose) printf("%s call VSchemaRelease\n", __func__); VSchemaRelease (schema); } if (verbose) printf("%s call VDBManagerRelease\n", __func__); VDBManagerRelease (mgr); } return rc; }
/* LoadSchema * looks in metadata for stored schema */ static rc_t CC VPhysicalLoadV1Schema ( VPhysical *self, VTypedecl *td, VSchema *schema, const KMDataNode *node ) { rc_t rc; KMDataNodeSchemaFillData pb; pb . node = node; pb . pos = 0; pb . add_v0 = true; /* add stored declaration to cursor schema */ rc = VSchemaParseTextCallback ( schema, "VPhysicalLoadV1Schema", KMDataNodeFillSchema, & pb ); if ( rc == 0 ) { size_t size; char type_expr [ 256 ]; /* retrieve and resolve "type" attribute */ rc = KMDataNodeReadAttr ( node, "type", type_expr, sizeof type_expr, & size ); if ( rc == 0 ) rc = VSchemaResolveTypedecl ( schema, td, type_expr ); /* if a decoding schema exists */ if ( rc == 0 && pb . pos != 0 ) { char sphysical_name [ 512 ]; /* preserve schema function expression */ size_t decoding_xsize; char decoding_expr [ 256 ]; rc = KMDataNodeReadAttr ( node, "schema", decoding_expr, sizeof decoding_expr, & decoding_xsize ); if ( rc == 0 ) { /* look for "encoding" */ const KMDataNode *enc; rc = KMetadataOpenNodeRead ( self -> meta, & enc, "encoding" ); if ( rc == 0 ) { #if ALLOW_V1_UPDATE if ( ! self -> read_only ) { /* add stored declaration to cursor schema */ pb . node = enc; pb . pos = 0; pb . add_v0 = true; rc = VSchemaParseTextCallback ( schema, "VPhysicalLoadV1Schema", KMDataNodeFillSchema, & pb ); } if ( rc == 0 ) #endif { /* preserve schema function expression */ size_t encoding_xsize; char encoding_expr [ 256 ], enc_type [ 256 ]; rc = KMDataNodeReadAttr ( enc, "schema", encoding_expr, sizeof encoding_expr, & encoding_xsize ); if ( rc == 0 ) { rc = KMDataNodeReadAttr ( enc, "type", enc_type, sizeof enc_type, & size ); } if ( rc == 0 ) { #if ALLOW_V1_UPDATE if ( self -> read_only ) { #endif /* build sphysical name */ sprintf ( sphysical_name, "%s_only", decoding_expr ); /* build physical decl */ pb . pos = sprintf ( pb . buff, "version 1;" "physical %s %s:phys#1" "{decode{%s k=@;return %s(k);}}" , type_expr , sphysical_name , enc_type , decoding_expr ); #if ALLOW_V1_UPDATE } else { /* strip off common namespace */ size_t i, ns_size; string_match ( decoding_expr, decoding_xsize, encoding_expr, encoding_xsize, -1, & ns_size ); if ( ns_size != 0 ) { char *p = string_rchr ( decoding_expr, ns_size, ':' ); ns_size = ( p == NULL ) ? 0U : ( uint32_t ) ( p - decoding_expr ) + 1U; } /* build sphysical name */ sprintf ( sphysical_name, "%s_%s", decoding_expr, & encoding_expr [ ns_size ] ); for ( i = ns_size; sphysical_name [ i ] != 0; ++ i ) { if ( sphysical_name [ i ] == ':' ) sphysical_name [ i ] = '_'; } /* build physical decl */ pb . pos = sprintf ( pb . buff, "version 1;" "physical %s %s:phys#1" "{encode{return %s(@);}" "decode{%s k=@;return %s(k);}}" , type_expr , sphysical_name , encoding_expr , enc_type , decoding_expr ); } #endif } } KMDataNodeRelease ( enc ); } else if ( GetRCState ( rc ) == rcNotFound ) { /* build sphysical name */ sprintf ( sphysical_name, "%s_only", decoding_expr ); /* build decode-only physical decl */ pb . pos = sprintf ( pb . buff, "version 1;" "physical %s %s:phys#1" "{decode{opaque k=@;return %s(k);}}" , type_expr , sphysical_name , decoding_expr ); rc = 0; } if ( rc == 0 ) { /* parse synthesized schema into cursor VSchema */ rc = VSchemaParseText ( schema, "VPhysicalLoadV1Schema", pb . buff, pb . pos ); if ( rc == 0 ) { VTypedecl etd; /* create a new expression object */ sprintf ( pb . buff, "%s:phys#1", sphysical_name ); rc = VSchemaImplicitPhysEncExpr ( schema, & etd, & self -> enc, pb . buff, "VPhysicalLoadV1Schema" ); if ( rc != 0 ) { PLOGERR ( klogInt, ( klogInt, rc, "failed to establish column type from '$(expr)'", "expr=%s", pb . buff )); } else if ( self -> smbr != NULL && self -> smbr -> type == NULL ) { /* back-patch schema */ ( ( SPhysMember* ) self -> smbr ) -> type = self -> enc; atomic32_inc ( & ( ( SExpression* ) self -> enc ) -> refcount ); } } } } } } KMDataNodeRelease ( node ); return rc; }