1 /* TDB tools to create various canned database layouts. */
7 struct tdb_layout *new_tdb_layout(void)
9 struct tdb_layout *layout = malloc(sizeof(*layout));
10 layout->num_elems = 0;
12 layout->ftable = layout->htable = -1;
16 static void add(struct tdb_layout *layout, union tdb_layout_elem elem)
18 layout->elem = realloc(layout->elem,
19 sizeof(layout->elem[0])
20 * (layout->num_elems+1));
21 layout->elem[layout->num_elems++] = elem;
24 void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len)
26 union tdb_layout_elem elem;
27 elem.base.type = FREE;
32 static struct tdb_data dup_key(struct tdb_data key)
35 ret.dsize = key.dsize;
36 ret.dptr = malloc(ret.dsize);
37 memcpy(ret.dptr, key.dptr, ret.dsize);
41 void tdb_layout_add_used(struct tdb_layout *layout,
42 TDB_DATA key, TDB_DATA data,
45 union tdb_layout_elem elem;
46 elem.base.type = DATA;
47 elem.used.key = dup_key(key);
48 elem.used.data = dup_key(data);
49 elem.used.extra = extra;
53 void tdb_layout_add_hashtable(struct tdb_layout *layout,
54 unsigned int hash_bits,
57 union tdb_layout_elem elem;
58 elem.base.type = HASHTABLE;
59 elem.hashtable.hash_bits = hash_bits;
60 elem.hashtable.extra = extra;
61 assert(layout->htable == -1U);
62 layout->htable = layout->num_elems;
66 void tdb_layout_add_freetable(struct tdb_layout *layout,
67 unsigned int num_zones,
68 unsigned int zone_bits,
69 unsigned int num_buckets,
72 union tdb_layout_elem elem;
73 elem.base.type = FREETABLE;
74 elem.freetable.num_zones = num_zones;
75 elem.freetable.zone_bits = zone_bits;
76 elem.freetable.num_buckets = num_buckets;
77 elem.freetable.extra = extra;
78 assert(layout->ftable == -1U);
79 layout->ftable = layout->num_elems;
83 static tdb_len_t free_record_len(tdb_len_t len)
85 return sizeof(struct tdb_used_record) + len;
88 static tdb_len_t data_record_len(struct tle_used *used)
91 len = sizeof(struct tdb_used_record)
92 + used->key.dsize + used->data.dsize + used->extra;
93 assert(len >= sizeof(struct tdb_free_record));
97 static tdb_len_t hashtable_len(struct tle_hashtable *htable)
99 return sizeof(struct tdb_used_record)
100 + (sizeof(tdb_off_t) << htable->hash_bits);
103 static tdb_len_t freetable_len(struct tle_freetable *ftable)
105 return sizeof(struct tdb_used_record)
106 + (sizeof(tdb_off_t) * ftable->num_zones
107 * (ftable->num_buckets + 1));
110 static void set_free_record(void *mem, tdb_len_t len)
112 /* We do all the work in add_to_freetable */
115 static void set_data_record(void *mem, struct tdb_context *tdb,
116 struct tle_used *used)
118 struct tdb_used_record *u = mem;
120 set_header(tdb, u, used->key.dsize, used->data.dsize,
121 used->key.dsize + used->data.dsize + used->extra,
122 tdb_hash(tdb, used->key.dptr, used->key.dsize));
123 memcpy(u + 1, used->key.dptr, used->key.dsize);
124 memcpy((char *)(u + 1) + used->key.dsize,
125 used->data.dptr, used->data.dsize);
128 static void set_hashtable(void *mem, struct tdb_context *tdb,
129 struct tle_hashtable *htable)
131 struct tdb_used_record *u = mem;
132 tdb_len_t len = sizeof(tdb_off_t) << htable->hash_bits;
134 set_header(tdb, u, 0, len, len + htable->extra, 0);
135 memset(u + 1, 0, len);
138 static void set_freetable(void *mem, struct tdb_context *tdb,
139 struct tle_freetable *ftable)
141 struct tdb_used_record *u = mem;
142 tdb_len_t len = sizeof(tdb_off_t) * ftable->num_zones
143 * (ftable->num_buckets + 1);
144 set_header(tdb, u, 0, len, len + ftable->extra, 0);
145 memset(u + 1, 0, len);
148 static void add_to_freetable(struct tdb_context *tdb,
152 add_free_record(tdb, eoff, sizeof(struct tdb_used_record) + elen);
155 static tdb_off_t hash_off(struct tdb_context *tdb, uint64_t list)
157 return tdb->header.v.hash_off
158 + ((list & ((1ULL << tdb->header.v.hash_bits) - 1))
159 * sizeof(tdb_off_t));
162 static void add_to_hashtable(struct tdb_context *tdb,
166 uint64_t hash = tdb_hash(tdb, key.dptr, key.dsize);
169 while (tdb_read_off(tdb, hoff = hash_off(tdb, hash)) != 0)
172 tdb_write_off(tdb, hoff, eoff);
175 /* FIXME: Support TDB_CONVERT */
176 struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
180 struct tdb_header *hdr;
182 struct tdb_context *tdb;
184 assert(layout->ftable != -1U);
185 assert(layout->htable != -1U);
187 len = sizeof(struct tdb_header);
189 /* First pass of layout: calc lengths */
190 for (i = 0; i < layout->num_elems; i++) {
191 union tdb_layout_elem *e = &layout->elem[i];
193 switch (e->base.type) {
195 len += free_record_len(e->free.len);
198 len += data_record_len(&e->used);
201 len += hashtable_len(&e->hashtable);
204 len += freetable_len(&e->freetable);
210 /* Now populate our header, cribbing from a real TDB header. */
211 tdb = tdb_open(NULL, TDB_INTERNAL, O_RDWR, 0, NULL);
215 hdr->v.num_zones = layout->elem[layout->ftable].freetable.num_zones;
216 hdr->v.zone_bits = layout->elem[layout->ftable].freetable.zone_bits;
218 = layout->elem[layout->ftable].freetable.num_buckets;
219 hdr->v.free_off = layout->elem[layout->ftable].base.off
220 + sizeof(struct tdb_used_record);
221 hdr->v.hash_bits = layout->elem[layout->htable].hashtable.hash_bits;
222 hdr->v.hash_off = layout->elem[layout->htable].base.off
223 + sizeof(struct tdb_used_record);
225 /* Mug the tdb we have to make it use this. */
231 for (i = 0; i < layout->num_elems; i++) {
232 union tdb_layout_elem *e = &layout->elem[i];
233 switch (e->base.type) {
235 set_free_record(mem + e->base.off, e->free.len);
238 set_data_record(mem + e->base.off, tdb, &e->used);
241 set_hashtable(mem + e->base.off, tdb, &e->hashtable);
244 set_freetable(mem + e->base.off, tdb, &e->freetable);
249 /* Now fill the free and hash tables. */
250 for (i = 0; i < layout->num_elems; i++) {
251 union tdb_layout_elem *e = &layout->elem[i];
252 switch (e->base.type) {
254 add_to_freetable(tdb, e->base.off, e->free.len);
257 add_to_hashtable(tdb, e->base.off, e->used.key);