1 /* TDB tools to create various canned database layouts. */
8 struct tdb_layout *new_tdb_layout(void)
10 struct tdb_layout *layout = malloc(sizeof(*layout));
11 layout->num_elems = 0;
17 static void add(struct tdb_layout *layout, union tdb_layout_elem elem)
19 layout->elem = realloc(layout->elem,
20 sizeof(layout->elem[0])
21 * (layout->num_elems+1));
22 layout->elem[layout->num_elems++] = elem;
25 void tdb_layout_add_zone(struct tdb_layout *layout,
26 unsigned int zone_bits,
29 union tdb_layout_elem elem;
31 tdb_layout_add_free(layout, 0);
32 elem.base.type = ZONE;
33 elem.zone.zone_bits = zone_bits;
37 void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len)
39 union tdb_layout_elem elem;
40 elem.base.type = FREE;
45 static struct tdb_data dup_key(struct tdb_data key)
48 ret.dsize = key.dsize;
49 ret.dptr = malloc(ret.dsize);
50 memcpy(ret.dptr, key.dptr, ret.dsize);
54 void tdb_layout_add_used(struct tdb_layout *layout,
55 TDB_DATA key, TDB_DATA data,
58 union tdb_layout_elem elem;
59 elem.base.type = DATA;
60 elem.used.key = dup_key(key);
61 elem.used.data = dup_key(data);
62 elem.used.extra = extra;
66 void tdb_layout_add_hashtable(struct tdb_layout *layout,
67 unsigned int hash_bits,
70 union tdb_layout_elem elem;
71 elem.base.type = HASHTABLE;
72 elem.hashtable.hash_bits = hash_bits;
73 elem.hashtable.extra = extra;
74 assert(layout->htable == -1U);
75 layout->htable = layout->num_elems;
79 static tdb_len_t free_record_len(tdb_len_t len)
81 return sizeof(struct tdb_used_record) + len;
84 static tdb_len_t data_record_len(struct tle_used *used)
87 len = sizeof(struct tdb_used_record)
88 + used->key.dsize + used->data.dsize + used->extra;
89 assert(len >= sizeof(struct tdb_free_record));
93 static tdb_len_t hashtable_len(struct tle_hashtable *htable)
95 return sizeof(struct tdb_used_record)
96 + (sizeof(tdb_off_t) << htable->hash_bits);
99 static tdb_len_t zone_header_len(struct tle_zone *zone)
101 return sizeof(struct free_zone_header)
102 + sizeof(tdb_off_t) * (BUCKETS_FOR_ZONE(zone->zone_bits)+1);
105 static void set_free_record(void *mem, tdb_len_t len)
107 /* We do all the work in add_to_freetable */
110 static void set_data_record(void *mem, struct tdb_context *tdb,
111 struct tle_zone *last_zone,
112 struct tle_used *used)
114 struct tdb_used_record *u = mem;
116 set_header(tdb, u, used->key.dsize, used->data.dsize,
117 used->key.dsize + used->data.dsize + used->extra,
118 tdb_hash(tdb, used->key.dptr, used->key.dsize),
119 last_zone->zone_bits);
120 memcpy(u + 1, used->key.dptr, used->key.dsize);
121 memcpy((char *)(u + 1) + used->key.dsize,
122 used->data.dptr, used->data.dsize);
125 static void set_hashtable(void *mem, struct tdb_context *tdb,
126 struct tle_zone *last_zone,
127 struct tle_hashtable *htable)
129 struct tdb_used_record *u = mem;
130 tdb_len_t len = sizeof(tdb_off_t) << htable->hash_bits;
132 set_header(tdb, u, 0, len, len + htable->extra, 0,
133 last_zone->zone_bits);
134 memset(u + 1, 0, len);
137 static void set_zone(void *mem, struct tdb_context *tdb,
138 struct tle_zone *zone)
140 struct free_zone_header *fz = mem;
141 memset(fz, 0, zone_header_len(zone));
142 fz->zone_bits = zone->zone_bits;
145 static void add_to_freetable(struct tdb_context *tdb,
146 struct tle_zone *last_zone,
150 add_free_record(tdb, last_zone->zone_bits, eoff,
151 sizeof(struct tdb_used_record) + elen);
154 static void add_to_hashtable(struct tdb_context *tdb,
158 uint64_t hash = tdb_hash(tdb, key.dptr, key.dsize);
161 while (tdb_read_off(tdb, hoff = hash_off(tdb, hash)) != 0)
164 tdb_write_off(tdb, hoff, eoff);
167 /* FIXME: Support TDB_CONVERT */
168 struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
173 struct tdb_header *hdr;
175 struct tdb_context *tdb;
176 struct tle_zone *last_zone = NULL;
178 assert(layout->htable != -1U);
179 assert(layout->elem[0].base.type == ZONE);
182 off = sizeof(struct tdb_header);
184 /* First pass of layout: calc lengths */
185 for (i = 0; i < layout->num_elems; i++) {
186 union tdb_layout_elem *e = &layout->elem[i];
188 switch (e->base.type) {
190 assert(zone_left == 0);
191 len = zone_header_len(&e->zone);
192 zone_left = 1ULL << e->zone.zone_bits;
195 if (e->free.len == 0)
196 e->free.len = zone_left
197 - sizeof(struct tdb_used_record);
198 len = free_record_len(e->free.len);
201 len = data_record_len(&e->used);
204 len = hashtable_len(&e->hashtable);
208 assert(zone_left >= len);
212 /* Fill final zone with free record. */
213 if (zone_left != 0) {
214 tdb_layout_add_free(layout,
216 - sizeof(struct tdb_used_record));
217 layout->elem[layout->num_elems-1].base.off = off;
222 /* Now populate our header, cribbing from a real TDB header. */
223 tdb = tdb_open(NULL, TDB_INTERNAL, O_RDWR, 0, &tap_log_attr);
227 hdr->v.hash_bits = layout->elem[layout->htable].hashtable.hash_bits;
228 hdr->v.hash_off = layout->elem[layout->htable].base.off
229 + sizeof(struct tdb_used_record);
231 /* Mug the tdb we have to make it use this. */
234 tdb->map_size = off+1;
237 for (i = 0; i < layout->num_elems; i++) {
238 union tdb_layout_elem *e = &layout->elem[i];
239 switch (e->base.type) {
241 set_zone(mem + e->base.off, tdb, &e->zone);
242 last_zone = &e->zone;
245 set_free_record(mem + e->base.off, e->free.len);
248 set_data_record(mem + e->base.off, tdb, last_zone,
252 set_hashtable(mem + e->base.off, tdb, last_zone,
258 /* Now fill the free and hash tables. */
259 for (i = 0; i < layout->num_elems; i++) {
260 union tdb_layout_elem *e = &layout->elem[i];
261 switch (e->base.type) {
263 last_zone = &e->zone;
266 add_to_freetable(tdb, last_zone,
267 e->base.off, e->free.len);
270 add_to_hashtable(tdb, e->base.off, e->used.key);
278 ((uint8_t *)tdb->map_ptr)[tdb->map_size-1] = last_zone->zone_bits;