Branch data Line data Source code
1 : : /* cdb_make.c: basic cdb creation routines
2 : : *
3 : : * This file is a part of tinycdb package.
4 : : * Copyright (C) 2001-2023 Michael Tokarev <mjt+cdb@corpit.ru>
5 : : *
6 : : * Permission is hereby granted, free of charge, to any person obtaining a
7 : : * copy of this software and associated documentation files (the "Software"),
8 : : * to deal in the Software without restriction, including without limitation
9 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 : : * and/or sell copies of the Software, and to permit persons to whom the
11 : : * Software is furnished to do so, subject to the following conditions:
12 : : *
13 : : * The above copyright notice and this permission notice shall be included
14 : : * in all copies or substantial portions of the Software.
15 : : *
16 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 : : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 : : * DEALINGS IN THE SOFTWARE.
23 : : */
24 : :
25 : : #include <unistd.h>
26 : : #include <stdlib.h>
27 : : #include <string.h>
28 : : #include "cdb_int.h"
29 : :
30 : : int
31 : 9 : cdb_make_start(struct cdb_make *cdbmp, int fd)
32 : : {
33 : 9 : memset(cdbmp, 0, sizeof(*cdbmp));
34 : 9 : cdbmp->cdb_fd = fd;
35 : 9 : cdbmp->cdb_dpos = 2048;
36 : 9 : cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048;
37 : 9 : return lseek(fd, 0, SEEK_SET);
38 : : }
39 : :
40 : : int internal_function
41 : 18 : _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len)
42 : : {
43 [ + + ]: 36 : while(len) {
44 : 18 : int l = write(fd, buf, len);
45 [ + - ]: 18 : if (l > 0) {
46 : 18 : len -= l;
47 : 18 : buf += l;
48 : : }
49 [ # # # # ]: 0 : else if (l < 0 && errno != EINTR)
50 : 0 : return -1;
51 : : }
52 : 18 : return 0;
53 : : }
54 : :
55 : : int internal_function
56 : 9 : _cdb_make_flush(struct cdb_make *cdbmp) {
57 : 9 : unsigned len = cdbmp->cdb_bpos - cdbmp->cdb_buf;
58 [ + - ]: 9 : if (len) {
59 [ - + ]: 9 : if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, len) < 0)
60 : 0 : return -1;
61 : 9 : cdbmp->cdb_bpos = cdbmp->cdb_buf;
62 : : }
63 : 9 : return 0;
64 : : }
65 : :
66 : : int internal_function
67 : 32 : _cdb_make_write(struct cdb_make *cdbmp, const unsigned char *ptr, unsigned len)
68 : : {
69 : 32 : unsigned l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf);
70 : 32 : cdbmp->cdb_dpos += len;
71 [ - + ]: 32 : if (len > l) {
72 : 0 : memcpy(cdbmp->cdb_bpos, ptr, l);
73 : 0 : cdbmp->cdb_bpos += l;
74 [ # # ]: 0 : if (_cdb_make_flush(cdbmp) < 0)
75 : 0 : return -1;
76 : 0 : ptr += l; len -= l;
77 : 0 : l = len / sizeof(cdbmp->cdb_buf);
78 [ # # ]: 0 : if (l) {
79 : 0 : l *= sizeof(cdbmp->cdb_buf);
80 [ # # ]: 0 : if (_cdb_make_fullwrite(cdbmp->cdb_fd, ptr, l) < 0)
81 : 0 : return -1;
82 : 0 : ptr += l; len -= l;
83 : : }
84 : : }
85 [ + + ]: 32 : if (len) {
86 : 26 : memcpy(cdbmp->cdb_bpos, ptr, len);
87 : 26 : cdbmp->cdb_bpos += len;
88 : : }
89 : 32 : return 0;
90 : : }
91 : :
92 : : static int
93 : 9 : cdb_make_finish_internal(struct cdb_make *cdbmp)
94 : : {
95 : : unsigned hcnt[256]; /* hash table counts */
96 : : unsigned hpos[256]; /* hash table positions */
97 : : struct cdb_rec *htab;
98 : : unsigned char *p;
99 : : struct cdb_rl *rl;
100 : : unsigned hsize;
101 : : unsigned t, i;
102 : :
103 [ - + ]: 9 : if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt)
104 : 0 : return errno = ENOMEM, -1;
105 : :
106 : : /* count htab sizes and reorder reclists */
107 : 9 : hsize = 0;
108 [ + + ]: 2313 : for (t = 0; t < 256; ++t) {
109 : 2304 : struct cdb_rl *rlt = NULL;
110 : 2304 : i = 0;
111 : 2304 : rl = cdbmp->cdb_rec[t];
112 [ + + ]: 2312 : while(rl) {
113 : 8 : struct cdb_rl *rln = rl->next;
114 : 8 : rl->next = rlt;
115 : 8 : rlt = rl;
116 : 8 : i += rl->cnt;
117 : 8 : rl = rln;
118 : : }
119 : 2304 : cdbmp->cdb_rec[t] = rlt;
120 [ + + ]: 2304 : if (hsize < (hcnt[t] = i << 1))
121 : 6 : hsize = hcnt[t];
122 : : }
123 : :
124 : : /* allocate memory to hold max htable */
125 : 9 : htab = (struct cdb_rec*)malloc((hsize + 2) * sizeof(struct cdb_rec));
126 [ - + ]: 9 : if (!htab)
127 : 0 : return errno = ENOENT, -1;
128 : 9 : p = (unsigned char *)htab;
129 : 9 : htab += 2;
130 : :
131 : : /* build hash tables */
132 [ + + ]: 2313 : for (t = 0; t < 256; ++t) {
133 : : unsigned len, hi;
134 : 2304 : hpos[t] = cdbmp->cdb_dpos;
135 [ + + ]: 2304 : if ((len = hcnt[t]) == 0)
136 : 2296 : continue;
137 [ + + ]: 24 : for (i = 0; i < len; ++i)
138 : 16 : htab[i].hval = htab[i].rpos = 0;
139 [ + + ]: 16 : for (rl = cdbmp->cdb_rec[t]; rl; rl = rl->next)
140 [ + + ]: 16 : for (i = 0; i < rl->cnt; ++i) {
141 : 8 : hi = (rl->rec[i].hval >> 8) % len;
142 [ - + ]: 16 : while(htab[hi].rpos)
143 [ # # ]: 0 : if (++hi == len)
144 : 0 : hi = 0;
145 : 8 : htab[hi] = rl->rec[i];
146 : : }
147 [ + + ]: 24 : for (i = 0; i < len; ++i) {
148 : 16 : cdb_pack(htab[i].hval, p + (i << 3));
149 : 16 : cdb_pack(htab[i].rpos, p + (i << 3) + 4);
150 : : }
151 [ - + ]: 8 : if (_cdb_make_write(cdbmp, p, len << 3) < 0) {
152 : 0 : free(p);
153 : 0 : return -1;
154 : : }
155 : : }
156 : 9 : free(p);
157 [ - + ]: 9 : if (_cdb_make_flush(cdbmp) < 0)
158 : 0 : return -1;
159 : 9 : p = cdbmp->cdb_buf;
160 [ + + ]: 2313 : for (t = 0; t < 256; ++t) {
161 : 2304 : cdb_pack(hpos[t], p + (t << 3));
162 : 2304 : cdb_pack(hcnt[t], p + (t << 3) + 4);
163 : : }
164 [ + - - + ]: 18 : if (lseek(cdbmp->cdb_fd, 0, SEEK_SET) != 0 ||
165 : 9 : _cdb_make_fullwrite(cdbmp->cdb_fd, p, 2048) != 0)
166 : 0 : return -1;
167 : :
168 : 9 : return fsync(cdbmp->cdb_fd);
169 : : }
170 : :
171 : : static void
172 : 9 : cdb_make_free(struct cdb_make *cdbmp)
173 : : {
174 : : unsigned t;
175 [ + + ]: 2313 : for(t = 0; t < 256; ++t) {
176 : 2304 : struct cdb_rl *rl = cdbmp->cdb_rec[t];
177 [ + + ]: 2312 : while(rl) {
178 : 8 : struct cdb_rl *tm = rl;
179 : 8 : rl = rl->next;
180 : 8 : free(tm);
181 : : }
182 : : }
183 : 9 : }
184 : :
185 : : int
186 : 9 : cdb_make_finish(struct cdb_make *cdbmp)
187 : : {
188 : 9 : int r = cdb_make_finish_internal(cdbmp);
189 : 9 : cdb_make_free(cdbmp);
190 : 9 : return r;
191 : : }
192 : :
|