1 /* NTDB tools to create various canned database layouts. */
6 #include <ccan/err/err.h>
9 struct ntdb_layout
*new_ntdb_layout(void)
11 struct ntdb_layout
*layout
= malloc(sizeof(*layout
));
12 layout
->num_elems
= 0;
17 static void add(struct ntdb_layout
*layout
, union ntdb_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 ntdb_layout_add_freetable(struct ntdb_layout
*layout
)
27 union ntdb_layout_elem elem
;
28 elem
.base
.type
= FREETABLE
;
32 void ntdb_layout_add_free(struct ntdb_layout
*layout
, ntdb_len_t len
,
35 union ntdb_layout_elem elem
;
36 elem
.base
.type
= FREE
;
38 elem
.free
.ftable_num
= ftable
;
42 void ntdb_layout_add_capability(struct ntdb_layout
*layout
,
49 union ntdb_layout_elem elem
;
50 elem
.base
.type
= CAPABILITY
;
51 elem
.capability
.type
= type
;
53 elem
.capability
.type
|= NTDB_CAP_NOWRITE
;
55 elem
.capability
.type
|= NTDB_CAP_NOOPEN
;
57 elem
.capability
.type
|= NTDB_CAP_NOCHECK
;
58 elem
.capability
.extra
= extra
;
62 static NTDB_DATA
dup_key(NTDB_DATA key
)
65 ret
.dsize
= key
.dsize
;
66 ret
.dptr
= malloc(ret
.dsize
);
67 memcpy(ret
.dptr
, key
.dptr
, ret
.dsize
);
71 void ntdb_layout_add_used(struct ntdb_layout
*layout
,
72 NTDB_DATA key
, NTDB_DATA data
,
75 union ntdb_layout_elem elem
;
76 elem
.base
.type
= DATA
;
77 elem
.used
.key
= dup_key(key
);
78 elem
.used
.data
= dup_key(data
);
79 elem
.used
.extra
= extra
;
83 static ntdb_len_t
free_record_len(ntdb_len_t len
)
85 return sizeof(struct ntdb_used_record
) + len
;
88 static ntdb_len_t
data_record_len(struct tle_used
*used
)
91 len
= sizeof(struct ntdb_used_record
)
92 + used
->key
.dsize
+ used
->data
.dsize
+ used
->extra
;
93 assert(len
>= sizeof(struct ntdb_free_record
));
97 static ntdb_len_t
capability_len(struct tle_capability
*cap
)
99 return sizeof(struct ntdb_capability
) + cap
->extra
;
102 static ntdb_len_t
freetable_len(struct tle_freetable
*ftable
)
104 return sizeof(struct ntdb_freetable
);
107 static void set_free_record(void *mem
, ntdb_len_t len
)
109 /* We do all the work in add_to_freetable */
112 static void add_zero_pad(struct ntdb_used_record
*u
, size_t len
, size_t extra
)
115 ((char *)(u
+ 1))[len
] = '\0';
118 static void set_data_record(void *mem
, struct ntdb_context
*ntdb
,
119 struct tle_used
*used
)
121 struct ntdb_used_record
*u
= mem
;
123 set_header(ntdb
, u
, NTDB_USED_MAGIC
, used
->key
.dsize
, used
->data
.dsize
,
124 used
->key
.dsize
+ used
->data
.dsize
+ used
->extra
);
125 memcpy(u
+ 1, used
->key
.dptr
, used
->key
.dsize
);
126 memcpy((char *)(u
+ 1) + used
->key
.dsize
,
127 used
->data
.dptr
, used
->data
.dsize
);
128 add_zero_pad(u
, used
->key
.dsize
+ used
->data
.dsize
, used
->extra
);
131 static void set_capability(void *mem
, struct ntdb_context
*ntdb
,
132 struct tle_capability
*cap
, struct ntdb_header
*hdr
,
135 struct ntdb_capability
*c
= mem
;
136 ntdb_len_t len
= sizeof(*c
) - sizeof(struct ntdb_used_record
) + cap
->extra
;
140 set_header(ntdb
, &c
->hdr
, NTDB_CAP_MAGIC
, 0, len
, len
);
142 /* Append to capability list. */
144 hdr
->capabilities
= cap
->base
.off
;
146 c
= (struct ntdb_capability
*)((char *)hdr
+ last_cap
);
147 c
->next
= cap
->base
.off
;
151 static void set_freetable(void *mem
, struct ntdb_context
*ntdb
,
152 struct tle_freetable
*freetable
, struct ntdb_header
*hdr
,
153 ntdb_off_t last_ftable
)
155 struct ntdb_freetable
*ftable
= mem
;
156 memset(ftable
, 0, sizeof(*ftable
));
157 set_header(ntdb
, &ftable
->hdr
, NTDB_FTABLE_MAGIC
, 0,
158 sizeof(*ftable
) - sizeof(ftable
->hdr
),
159 sizeof(*ftable
) - sizeof(ftable
->hdr
));
162 ftable
= (struct ntdb_freetable
*)((char *)hdr
+ last_ftable
);
163 ftable
->next
= freetable
->base
.off
;
165 hdr
->free_table
= freetable
->base
.off
;
169 static void add_to_freetable(struct ntdb_context
*ntdb
,
173 struct tle_freetable
*freetable
)
175 ntdb
->ftable_off
= freetable
->base
.off
;
176 ntdb
->ftable
= ftable
;
177 add_free_record(ntdb
, eoff
, sizeof(struct ntdb_used_record
) + elen
,
178 NTDB_LOCK_WAIT
, false);
181 /* Get bits from a value. */
182 static uint32_t bits(uint64_t val
, unsigned start
, unsigned num
)
185 return (val
>> start
) & ((1U << num
) - 1);
188 static ntdb_off_t
encode_offset(const struct ntdb_context
*ntdb
,
189 ntdb_off_t new_off
, uint32_t hash
)
193 assert((new_off
& (1ULL << NTDB_OFF_CHAIN_BIT
)) == 0);
194 assert((new_off
>> (64 - NTDB_OFF_UPPER_STEAL
)) == 0);
195 /* We pack extra hash bits into the upper bits of the offset. */
196 extra
= bits(hash
, ntdb
->hash_bits
, NTDB_OFF_UPPER_STEAL
);
197 extra
<<= (64 - NTDB_OFF_UPPER_STEAL
);
199 return new_off
| extra
;
202 static ntdb_off_t
hbucket_off(ntdb_len_t idx
)
204 return sizeof(struct ntdb_header
) + sizeof(struct ntdb_used_record
)
205 + idx
* sizeof(ntdb_off_t
);
208 /* FIXME: Our hash table handling here is primitive: we don't expand! */
209 static void add_to_hashtable(struct ntdb_context
*ntdb
,
214 uint32_t h
= ntdb_hash(ntdb
, key
.dptr
, key
.dsize
);
216 b_off
= hbucket_off(h
& ((1 << ntdb
->hash_bits
)-1));
217 if (ntdb_read_off(ntdb
, b_off
) != 0)
220 ntdb_write_off(ntdb
, b_off
, encode_offset(ntdb
, eoff
, h
));
223 static struct tle_freetable
*find_ftable(struct ntdb_layout
*layout
, unsigned num
)
227 for (i
= 0; i
< layout
->num_elems
; i
++) {
228 if (layout
->elem
[i
].base
.type
!= FREETABLE
)
231 return &layout
->elem
[i
].ftable
;
237 /* FIXME: Support NTDB_CONVERT */
238 struct ntdb_context
*ntdb_layout_get(struct ntdb_layout
*layout
,
239 void (*freefn
)(void *),
240 union ntdb_attribute
*attr
)
243 ntdb_off_t off
, hdrlen
, len
, last_ftable
, last_cap
;
245 struct ntdb_context
*ntdb
;
247 /* Now populate our header, cribbing from a real NTDB header. */
248 ntdb
= ntdb_open("layout", NTDB_INTERNAL
, O_RDWR
, 0, attr
);
250 off
= sizeof(struct ntdb_header
) + sizeof(struct ntdb_used_record
)
251 + (sizeof(ntdb_off_t
) << ntdb
->hash_bits
);
254 /* First pass of layout: calc lengths */
255 for (i
= 0; i
< layout
->num_elems
; i
++) {
256 union ntdb_layout_elem
*e
= &layout
->elem
[i
];
258 switch (e
->base
.type
) {
260 len
= freetable_len(&e
->ftable
);
263 len
= free_record_len(e
->free
.len
);
266 len
= data_record_len(&e
->used
);
269 len
= capability_len(&e
->capability
);
278 /* Fill with some weird pattern. */
279 memset(mem
, 0x99, off
);
280 memcpy(mem
, ntdb
->file
->map_ptr
, hdrlen
);
282 /* Mug the ntdb we have to make it use this. */
283 freefn(ntdb
->file
->map_ptr
);
284 ntdb
->file
->map_ptr
= mem
;
285 ntdb
->file
->map_size
= off
;
289 for (i
= 0; i
< layout
->num_elems
; i
++) {
290 union ntdb_layout_elem
*e
= &layout
->elem
[i
];
291 switch (e
->base
.type
) {
293 set_freetable(mem
+ e
->base
.off
, ntdb
, &e
->ftable
,
294 (struct ntdb_header
*)mem
, last_ftable
);
295 last_ftable
= e
->base
.off
;
298 set_free_record(mem
+ e
->base
.off
, e
->free
.len
);
301 set_data_record(mem
+ e
->base
.off
, ntdb
, &e
->used
);
304 set_capability(mem
+ e
->base
.off
, ntdb
, &e
->capability
,
305 (struct ntdb_header
*)mem
, last_cap
);
306 last_cap
= e
->base
.off
;
310 /* Must have a free table! */
313 /* Now fill the free and hash tables. */
314 for (i
= 0; i
< layout
->num_elems
; i
++) {
315 union ntdb_layout_elem
*e
= &layout
->elem
[i
];
316 switch (e
->base
.type
) {
318 add_to_freetable(ntdb
, e
->base
.off
, e
->free
.len
,
320 find_ftable(layout
, e
->free
.ftable_num
));
323 add_to_hashtable(ntdb
, e
->base
.off
, e
->used
.key
);
330 ntdb
->ftable_off
= find_ftable(layout
, 0)->base
.off
;
334 void ntdb_layout_write(struct ntdb_layout
*layout
, void (*freefn
)(void *),
335 union ntdb_attribute
*attr
, const char *filename
)
337 struct ntdb_context
*ntdb
= ntdb_layout_get(layout
, freefn
, attr
);
340 fd
= open(filename
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0600);
342 err(1, "opening %s for writing", filename
);
343 if (write(fd
, ntdb
->file
->map_ptr
, ntdb
->file
->map_size
)
344 != ntdb
->file
->map_size
)
345 err(1, "writing %s", filename
);
350 void ntdb_layout_free(struct ntdb_layout
*layout
)
354 for (i
= 0; i
< layout
->num_elems
; i
++) {
355 if (layout
->elem
[i
].base
.type
== DATA
) {
356 free(layout
->elem
[i
].used
.key
.dptr
);
357 free(layout
->elem
[i
].used
.data
.dptr
);