int exist_dtable::create(int dfd, const char * file, const params & config, dtable::iter * source, const ktable * shadow) { int e_dfd, r; params base_config, dnebase_config; const dtable_factory * base = dtable_factory::lookup(config, "base"); const dtable_factory * dnebase = dtable_factory::lookup(config, "dnebase"); if(!base || !dnebase) return -ENOENT; if(!config.get("base_config", &base_config, params())) return -EINVAL; if(!config.get("dnebase_config", &dnebase_config, params())) return -EINVAL; if(!source_shadow_ok(source, shadow)) return -EINVAL; r = mkdirat(dfd, file, 0755); if(r < 0) return r; e_dfd = openat(dfd, file, O_RDONLY); if(e_dfd < 0) goto fail_open; /* just to be sure */ source->first(); { dtable_skip_iter<dne_skip_test> base_source(source); r = base->create(e_dfd, "base", base_config, &base_source, NULL); if(r < 0) goto fail_base; } source->first(); { full_ktable full_shadow(source); nonshadow_skip_test skip_test(shadow); dtable_skip_iter<nonshadow_skip_test> dnebase_source(source, skip_test); r = dnebase->create(e_dfd, "dnebase", dnebase_config, &dnebase_source, &full_shadow); if(r < 0) goto fail_dnebase; } close(e_dfd); return 0; fail_dnebase: util::rm_r(e_dfd, "base"); fail_base: close(e_dfd); fail_open: unlinkat(dfd, file, AT_REMOVEDIR); return (r < 0) ? r : -1; }
int btree_dtable::create(int dfd, const char * file, const params & config, dtable::iter * source, const ktable * shadow) { int bt_dfd, r; params base_config; dtable * base_dtable; const dtable_factory * base = dtable_factory::lookup(config, "base"); if(!base) return -ENOENT; if(!config.get("base_config", &base_config, params())) return -EINVAL; if(!base->indexed_access(base_config)) return -ENOSYS; if(!source_shadow_ok(source, shadow)) return -EINVAL; r = mkdirat(dfd, file, 0755); if(r < 0) return r; bt_dfd = openat(dfd, file, O_RDONLY); if(bt_dfd < 0) goto fail_open; r = base->create(bt_dfd, "base", base_config, source, shadow); if(r < 0) goto fail_create; base_dtable = base->open(bt_dfd, "base", base_config, NULL); if(!base_dtable) goto fail_reopen; r = write_btree(bt_dfd, "btree", base_dtable); if(r < 0) goto fail_write; base_dtable->destroy(); close(bt_dfd); return 0; fail_write: base_dtable->destroy(); fail_reopen: util::rm_r(bt_dfd, "base"); fail_create: close(bt_dfd); fail_open: unlinkat(dfd, file, AT_REMOVEDIR); return (r < 0) ? r : -1; }
int exception_dtable::create(int dfd, const char * file, const params & config, dtable::iter * source, const ktable * shadow) { int excp_dfd, r; memory_dtable alt_mdt; reject_iter * handler; params base_config, alt_config; blob reject_value; const dtable_factory * base = dtable_factory::lookup(config, "base"); const dtable_factory * alt = dtable_factory::lookup(config, "alt"); if(!base || !alt) return -EINVAL; if(!config.get("base_config", &base_config, params())) return -EINVAL; if(!config.get("alt_config", &alt_config, params())) return -EINVAL; if(!config.get_blob_or_string("reject_value", &reject_value)) return -EINVAL; /* the reject value must exist, because nonexistent values * can get pruned out if the shadow does not require them */ if(!reject_value.exists()) return -EINVAL; if(!source_shadow_ok(source, shadow)) return -EINVAL; r = mkdirat(dfd, file, 0755); if(r < 0) return r; excp_dfd = openat(dfd, file, O_RDONLY); if(excp_dfd < 0) goto fail_open; /* we should really save the reject_value in a meta file here */ /* we'll always be appending, but it's faster if we say false here */ r = alt_mdt.init(source->key_type(), false, true); if(r < 0) goto fail_mdt; if(source->get_blob_cmp()) alt_mdt.set_blob_cmp(source->get_blob_cmp()); handler = new reject_iter(source, &alt_mdt, reject_value); if(!handler) goto fail_mdt; r = base->create(excp_dfd, "base", base_config, handler, shadow); if(r < 0) goto fail_base; /* no shadow - this only has exceptions */ r = alt->create(excp_dfd, "alt", alt_config, &alt_mdt, NULL); if(r < 0) goto fail_alt; delete handler; close(excp_dfd); return 0; fail_alt: util::rm_r(excp_dfd, "base"); fail_base: delete handler; fail_mdt: close(excp_dfd); fail_open: unlinkat(dfd, file, AT_REMOVEDIR); return -1; }
int simple_dtable::create(int dfd, const char * file, const params & config, dtable::iter * source, const ktable * shadow) { std::vector<istr> strings; std::vector<blob> blobs; dtype::ctype key_type = source->key_type(); const blob_comparator * blob_cmp = source->get_blob_cmp(); size_t key_count = 0, max_data_size = 0, total_data_size = 0; uint32_t max_key = 0; dtable_header header; int r, size; rwfile out; if(!source_shadow_ok(source, shadow)) return -EINVAL; /* just to be sure */ source->first(); while(source->valid()) { dtype key = source->key(); metablob meta = source->meta(); source->next(); if(!meta.exists()) /* omit non-existent entries no longer needed */ if(!shadow || !shadow->contains(key)) continue; key_count++; assert(key.type == key_type); switch(key.type) { case dtype::UINT32: if(key.u32 > max_key) max_key = key.u32; break; case dtype::DOUBLE: /* nothing to do */ break; case dtype::STRING: strings.push_back(key.str); break; case dtype::BLOB: blobs.push_back(key.blb); break; } if(meta.size() > max_data_size) max_data_size = meta.size(); total_data_size += meta.size(); } /* now write the file */ header.magic = SDTABLE_MAGIC; header.version = SDTABLE_VERSION; header.key_count = key_count; switch(key_type) { case dtype::UINT32: header.key_type = 1; header.key_size = util::byte_size(max_key); break; case dtype::DOUBLE: header.key_type = 2; header.key_size = sizeof(double); break; case dtype::STRING: header.key_type = 3; header.key_size = util::byte_size(strings.size() - 1); break; case dtype::BLOB: header.key_type = 4; header.key_size = util::byte_size(blobs.size() - 1); break; } /* we reserve size 0 for non-existent entries, so add 1 */ header.length_size = util::byte_size(max_data_size + 1); header.offset_size = util::byte_size(total_data_size); size = header.key_size + header.length_size + header.offset_size; r = out.create(dfd, file); if(r < 0) return r; r = out.append(&header); if(r < 0) goto fail_unlink; if(key_type == dtype::BLOB) { uint32_t length = blob_cmp ? strlen(blob_cmp->name) : 0; out.append(&length); if(length) out.append(blob_cmp->name); } if(key_type == dtype::STRING) { r = stringtbl::create(&out, strings); if(r < 0) goto fail_unlink; } else if(key_type == dtype::BLOB) { r = stringtbl::create(&out, blobs); if(r < 0) goto fail_unlink; } /* now the key array */ max_key = 0; total_data_size = 0; source->first(); while(source->valid()) { int i = 0; uint8_t bytes[size]; dtype key = source->key(); metablob meta = source->meta(); source->next(); if(!meta.exists()) /* omit non-existent entries no longer needed */ if(!shadow || !shadow->contains(key)) continue; switch(key.type) { case dtype::UINT32: util::layout_bytes(bytes, &i, key.u32, header.key_size); break; case dtype::DOUBLE: util::memcpy(bytes, &key.dbl, sizeof(double)); i += sizeof(double); break; case dtype::STRING: /* no need to locate the string; it's the next one */ util::layout_bytes(bytes, &i, max_key, header.key_size); max_key++; break; case dtype::BLOB: /* no need to locate the blob; it's the next one */ util::layout_bytes(bytes, &i, max_key, header.key_size); max_key++; break; } util::layout_bytes(bytes, &i, meta.exists() ? meta.size() + 1 : 0, header.length_size); util::layout_bytes(bytes, &i, total_data_size, header.offset_size); r = out.append(bytes, i); if(r != i) goto fail_unlink; total_data_size += meta.size(); } /* and the data itself */ source->first(); while(source->valid()) { blob value = source->value(); source->next(); /* nonexistent blobs have size 0 */ if(!value.size()) continue; r = out.append(value); if(r < 0) goto fail_unlink; } r = out.close(); if(r < 0) goto fail_unlink; return 0; fail_unlink: out.close(); unlinkat(dfd, file, 0); return (r < 0) ? r : -1; }
int deltaint_dtable::create(int dfd, const char * file, const params & config, dtable::iter * source, const ktable * shadow) { int r, di_dfd, skip; rev_iter_delta * rev; rev_iter_ref * ref; params base_config, ref_config; const dtable_factory * base = dtable_factory::lookup(config, "base"); const dtable_factory * reference = dtable_factory::lookup(config, "ref"); if(!base || !reference) return -ENOENT; if(!config.get("base_config", &base_config, params())) return -EINVAL; if(!config.get("ref_config", &ref_config, params())) return -EINVAL; if(!config.get("skip", &skip, 0) || skip < 2) return -EINVAL; if(!source_shadow_ok(source, shadow)) return -EINVAL; r = mkdirat(dfd, file, 0755); if(r < 0) return r; di_dfd = openat(dfd, file, O_RDONLY); if(di_dfd < 0) goto fail_open; rev = new rev_iter_delta(source); if(!rev) { r = -ENOMEM; goto fail_iter_1; } r = base->create(di_dfd, "base", base_config, rev, shadow); if(r < 0) goto fail_create_1; if(rev->failed) { r = -ENOSYS; goto fail_iter_2; } ref = new rev_iter_ref(source, skip); if(!ref) { r = -ENOMEM; goto fail_iter_2; } r = reference->create(di_dfd, "ref", ref_config, ref, NULL); if(r < 0) goto fail_create_2; delete ref; delete rev; close(di_dfd); return r; fail_create_2: delete ref; fail_iter_2: util::rm_r(di_dfd, "base"); fail_create_1: delete rev; fail_iter_1: close(di_dfd); fail_open: unlinkat(dfd, file, AT_REMOVEDIR); return (r < 0) ? r : -1; }