mas01cr@239
|
1 #include "audioDB.h"
|
mas01cr@404
|
2 extern "C" {
|
mas01cr@404
|
3 #include "audioDB_API.h"
|
mas01cr@404
|
4 }
|
mas01cr@404
|
5 #include "audioDB-internals.h"
|
mas01cr@404
|
6
|
mas01cr@404
|
7 static bool audiodb_enough_data_space_free(adb_t *adb, off_t size) {
|
mas01cr@404
|
8 adb_header_t *header = adb->header;
|
mas01cr@409
|
9 if(header->flags & O2_FLAG_LARGE_ADB) {
|
mas01cr@409
|
10 return true;
|
mas01cr@409
|
11 } else {
|
mas01cr@409
|
12 /* FIXME: timesTableOffset isn't necessarily the next biggest
|
mas01cr@409
|
13 * offset after dataOffset. Maybe make the offsets into an array
|
mas01cr@409
|
14 * that we can iterate over... */
|
mas01cr@409
|
15 return (header->timesTableOffset >
|
mas01cr@409
|
16 (header->dataOffset + header->length + size));
|
mas01cr@409
|
17 }
|
mas01cr@404
|
18 }
|
mas01cr@404
|
19
|
mas01cr@404
|
20 static bool audiodb_enough_per_file_space_free(adb_t *adb) {
|
mas01cr@404
|
21 /* FIXME: the comment above about the ordering of the tables applies
|
mas01cr@404
|
22 here too. */
|
mas01cr@404
|
23 adb_header_t *header = adb->header;
|
mas01cr@404
|
24 off_t file_table_length = header->trackTableOffset - header->fileTableOffset;
|
mas01cr@404
|
25 off_t track_table_length = header->dataOffset - header->trackTableOffset;
|
mas01cr@404
|
26 int fmaxfiles = file_table_length / O2_FILETABLE_ENTRY_SIZE;
|
mas01cr@404
|
27 int tmaxfiles = track_table_length / O2_TRACKTABLE_ENTRY_SIZE;
|
mas01cr@404
|
28 /* maxfiles is the _minimum_ of the two. Do not be confused... */
|
mas01cr@409
|
29 int maxfiles = fmaxfiles > tmaxfiles ? tmaxfiles : fmaxfiles;
|
mas01cr@409
|
30 if(header->flags & O2_FLAG_LARGE_ADB) {
|
mas01cr@409
|
31 /* by default, these tables are created with the same size as the
|
mas01cr@409
|
32 * fileTable (which should be called key_table); relying on that
|
mas01cr@409
|
33 * always being the case, though, smacks of optimism, so instead
|
mas01cr@409
|
34 * we code defensively... */
|
mas01cr@409
|
35 off_t data_table_length = header->timesTableOffset - header->dataOffset;
|
mas01cr@409
|
36 off_t times_table_length = header->powerTableOffset - header->timesTableOffset;
|
mas01cr@409
|
37 off_t power_table_length = header->dbSize - header->powerTableOffset;
|
mas01cr@409
|
38 int dmaxfiles = data_table_length / O2_FILETABLE_ENTRY_SIZE;
|
mas01cr@409
|
39 int timaxfiles = times_table_length / O2_FILETABLE_ENTRY_SIZE;
|
mas01cr@409
|
40 int pmaxfiles = power_table_length / O2_FILETABLE_ENTRY_SIZE;
|
mas01cr@409
|
41 /* ... even though it means a certain amount of tedium. */
|
mas01cr@409
|
42 maxfiles = maxfiles > dmaxfiles ? dmaxfiles : maxfiles;
|
mas01cr@409
|
43 maxfiles = maxfiles > timaxfiles ? timaxfiles : maxfiles;
|
mas01cr@409
|
44 maxfiles = maxfiles > pmaxfiles ? pmaxfiles : maxfiles;
|
mas01cr@409
|
45 }
|
mas01cr@409
|
46 return (header->numFiles < (unsigned int) maxfiles);
|
mas01cr@404
|
47 }
|
mas01cr@404
|
48
|
mas01cr@404
|
49 /*
|
mas01cr@404
|
50 * Hey, look, a comment. Normally I wouldn't bother, as the code
|
mas01cr@404
|
51 * should be self-documenting, but a lot of logic is concentrated in
|
mas01cr@404
|
52 * this one place, so let's give an overview beforehand. To insert a
|
mas01cr@404
|
53 * datum into the database, we:
|
mas01cr@404
|
54 *
|
mas01cr@404
|
55 * 1. check write permission;
|
mas01cr@409
|
56 * 2. check for enough space;
|
mas01cr@409
|
57 * 3. check that datum->dim and adb->header->dim agree (or that the
|
mas01cr@404
|
58 * header dimension is zero, in which case write datum->dim to
|
mas01cr@404
|
59 * adb->header->dim).
|
mas01cr@453
|
60 * 4. check for presence of datum->key in adb->keymap;
|
mas01cr@409
|
61 * 5. check for consistency between power and O2_FLAG_POWER, and
|
mas01cr@404
|
62 * times and O2_FLAG_TIMES;
|
mas01cr@409
|
63 * 6. write in data, power, times as appropriate; add to track
|
mas01cr@404
|
64 * and key tables too;
|
mas01cr@409
|
65 * 7. if O2_FLAG_L2NORM and !O2_FLAG_LARGE_ADB, compute norms and fill
|
mas01cr@409
|
66 * in table;
|
mas01cr@453
|
67 * 8. update adb->keys, adb->keymap, adb->track_lengths,
|
mas01cr@453
|
68 * adb->track_offsets and adb->header;
|
mas01cr@409
|
69 * 9. sync adb->header with disk.
|
mas01cr@404
|
70 *
|
mas01cr@409
|
71 * Step 9 essentially commits the transaction; until we update
|
mas01cr@408
|
72 * header->length, nothing will recognize the newly-written data. In
|
mas01cr@408
|
73 * principle, if it fails, we should roll back, which we can in fact
|
mas01cr@409
|
74 * do on the assumption that nothing in step 8 can ever fail; on the
|
mas01cr@408
|
75 * other hand, if it's failed, then it's unlikely that rolling back by
|
mas01cr@408
|
76 * syncing the original header back to disk is going to work
|
mas01cr@408
|
77 * desperately well. We should perhaps take an operating-system lock
|
mas01cr@409
|
78 * around step 9, so that we can't be interrupted part-way through
|
mas01cr@408
|
79 * (except of course for SIGKILL, but if we're hit with that we will
|
mas01cr@408
|
80 * always lose).
|
mas01cr@404
|
81 */
|
mas01cr@408
|
82 static int audiodb_insert_datum_internal(adb_t *adb, adb_datum_internal_t *datum) {
|
mas01cr@404
|
83
|
mas01cr@404
|
84 off_t size, offset, nfiles;
|
mas01cr@426
|
85 double *l2norm_buffer = NULL;
|
mas01cr@404
|
86
|
mas01cr@404
|
87 /* 1. check write permission; */
|
mas01cr@404
|
88 if(!(adb->flags & O_RDWR)) {
|
mas01cr@404
|
89 return 1;
|
mas01cr@404
|
90 }
|
mas01cr@409
|
91 /* 2. check for enough space; */
|
mas01cr@404
|
92 size = sizeof(double) * datum->nvectors * datum->dim;
|
mas01cr@404
|
93 if(!audiodb_enough_data_space_free(adb, size)) {
|
mas01cr@404
|
94 return 1;
|
mas01cr@404
|
95 }
|
mas01cr@404
|
96 if(!audiodb_enough_per_file_space_free(adb)) {
|
mas01cr@404
|
97 return 1;
|
mas01cr@404
|
98 }
|
mas01cr@409
|
99 /* 3. check that datum->dim and adb->header->dim agree (or that the
|
mas01cr@404
|
100 * header dimension is zero, in which case write datum->dim to
|
mas01cr@404
|
101 * adb->header->dim).
|
mas01cr@404
|
102 */
|
mas01cr@404
|
103 if(adb->header->dim == 0) {
|
mas01cr@404
|
104 adb->header->dim = datum->dim;
|
mas01cr@404
|
105 } else if (adb->header->dim != datum->dim) {
|
mas01cr@404
|
106 return 1;
|
mas01cr@404
|
107 }
|
mas01cr@453
|
108 /* 4. check for presence of datum->key in adb->keymap; */
|
mas01cr@453
|
109 if(adb->keymap->count(datum->key)) {
|
mas01cr@404
|
110 /* not part of an explicit API/ABI, but we need a distinguished
|
mas01cr@404
|
111 value in this circumstance to preserve somewhat wonky behaviour
|
mas01cr@404
|
112 of audioDB::batchinsert. */
|
mas01cr@404
|
113 return 2;
|
mas01cr@404
|
114 }
|
mas01cr@409
|
115 /* 5. check for consistency between power and O2_FLAG_POWER, and
|
mas01cr@404
|
116 * times and O2_FLAG_TIMES;
|
mas01cr@404
|
117 */
|
mas01cr@404
|
118 if((datum->power && !(adb->header->flags & O2_FLAG_POWER)) ||
|
mas01cr@404
|
119 ((adb->header->flags & O2_FLAG_POWER) && !datum->power)) {
|
mas01cr@404
|
120 return 1;
|
mas01cr@404
|
121 }
|
mas01cr@404
|
122 if(datum->times && !(adb->header->flags & O2_FLAG_TIMES)) {
|
mas01cr@404
|
123 if(adb->header->numFiles == 0) {
|
mas01cr@404
|
124 adb->header->flags |= O2_FLAG_TIMES;
|
mas01cr@404
|
125 } else {
|
mas01cr@404
|
126 return 1;
|
mas01cr@404
|
127 }
|
mas01cr@404
|
128 } else if ((adb->header->flags & O2_FLAG_TIMES) && !datum->times) {
|
mas01cr@404
|
129 return 1;
|
mas01cr@404
|
130 }
|
mas01cr@409
|
131 /* 6. write in data, power, times as appropriate; add to track
|
mas01cr@404
|
132 * and key tables too;
|
mas01cr@404
|
133 */
|
mas01cr@404
|
134 offset = adb->header->length;
|
mas01cr@404
|
135 nfiles = adb->header->numFiles;
|
mas01cr@404
|
136
|
mas01cr@410
|
137 /* FIXME: checking for all these lseek()s */
|
mas01cr@409
|
138 lseek(adb->fd, adb->header->fileTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
|
mas01cr@410
|
139 write_or_goto_error(adb->fd, datum->key, strlen(datum->key)+1);
|
mas01cr@404
|
140 lseek(adb->fd, adb->header->trackTableOffset + nfiles * O2_TRACKTABLE_ENTRY_SIZE, SEEK_SET);
|
mas01cr@410
|
141 write_or_goto_error(adb->fd, &datum->nvectors, O2_TRACKTABLE_ENTRY_SIZE);
|
mas01cr@409
|
142 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
|
mas01cr@409
|
143 char cwd[PATH_MAX];
|
mas01cr@409
|
144 char slash = '/';
|
mas01cr@404
|
145
|
mas01cr@410
|
146 if(!getcwd(cwd, PATH_MAX)) {
|
mas01cr@410
|
147 goto error;
|
mas01cr@410
|
148 }
|
mas01cr@409
|
149 lseek(adb->fd, adb->header->dataOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
|
mas01cr@409
|
150 if(*((char *) datum->data) != '/') {
|
mas01cr@410
|
151 write_or_goto_error(adb->fd, cwd, strlen(cwd));
|
mas01cr@410
|
152 write_or_goto_error(adb->fd, &slash, 1);
|
mas01cr@409
|
153 }
|
mas01cr@410
|
154 write_or_goto_error(adb->fd, datum->data, strlen((const char *) datum->data)+1);
|
mas01cr@409
|
155 if(datum->power) {
|
mas01cr@409
|
156 lseek(adb->fd, adb->header->powerTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
|
mas01cr@409
|
157 if(*((char *) datum->power) != '/') {
|
mas01cr@410
|
158 write_or_goto_error(adb->fd, cwd, strlen(cwd));
|
mas01cr@410
|
159 write_or_goto_error(adb->fd, &slash, 1);
|
mas01cr@409
|
160 }
|
mas01cr@410
|
161 write_or_goto_error(adb->fd, datum->power, strlen((const char *) datum->power)+1);
|
mas01cr@409
|
162 }
|
mas01cr@409
|
163 if(datum->times) {
|
mas01cr@409
|
164 lseek(adb->fd, adb->header->timesTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
|
mas01cr@409
|
165 if(*((char *) datum->times) != '/') {
|
mas01cr@410
|
166 write_or_goto_error(adb->fd, cwd, strlen(cwd));
|
mas01cr@410
|
167 write_or_goto_error(adb->fd, &slash, 1);
|
mas01cr@409
|
168 }
|
mas01cr@410
|
169 write_or_goto_error(adb->fd, datum->times, strlen((const char *) datum->times)+1);
|
mas01cr@409
|
170 }
|
mas01cr@409
|
171 } else {
|
mas01cr@409
|
172 lseek(adb->fd, adb->header->dataOffset + offset, SEEK_SET);
|
mas01cr@410
|
173 write_or_goto_error(adb->fd, datum->data, sizeof(double) * datum->nvectors * datum->dim);
|
mas01cr@409
|
174 if(datum->power) {
|
mas01cr@409
|
175 lseek(adb->fd, adb->header->powerTableOffset + offset / datum->dim, SEEK_SET);
|
mas01cr@410
|
176 write_or_goto_error(adb->fd, datum->power, sizeof(double) * datum->nvectors);
|
mas01cr@409
|
177 }
|
mas01cr@409
|
178 if(datum->times) {
|
mas01cr@409
|
179 lseek(adb->fd, adb->header->timesTableOffset + offset / datum->dim * 2, SEEK_SET);
|
mas01cr@410
|
180 write_or_goto_error(adb->fd, datum->times, sizeof(double) * datum->nvectors * 2);
|
mas01cr@409
|
181 }
|
mas01cr@409
|
182 }
|
mas01cr@409
|
183
|
mas01cr@409
|
184 /* 7. if O2_FLAG_L2NORM and !O2_FLAG_LARGE_ADB, compute norms and fill
|
mas01cr@409
|
185 * in table;
|
mas01cr@409
|
186 */
|
mas01cr@409
|
187 if((adb->header->flags & O2_FLAG_L2NORM) &&
|
mas01cr@409
|
188 !(adb->header->flags & O2_FLAG_LARGE_ADB)) {
|
mas01cr@408
|
189 l2norm_buffer = (double *) malloc(datum->nvectors * sizeof(double));
|
mas01cr@408
|
190
|
mas01cr@426
|
191 audiodb_l2norm_buffer((double *) datum->data, datum->dim, datum->nvectors, l2norm_buffer);
|
mas01cr@408
|
192 lseek(adb->fd, adb->header->l2normTableOffset + offset / datum->dim, SEEK_SET);
|
mas01cr@410
|
193 write_or_goto_error(adb->fd, l2norm_buffer, sizeof(double) * datum->nvectors);
|
mas01cr@408
|
194 free(l2norm_buffer);
|
mas01cr@410
|
195 l2norm_buffer = NULL;
|
mas01cr@404
|
196 }
|
mas01cr@404
|
197
|
mas01cr@453
|
198 /* 8. update adb->keys, adb->keymap, adb->track_lengths,
|
mas01cr@453
|
199 * adb->track_offsets and adb->header;
|
mas01cr@442
|
200 */
|
mas01cr@453
|
201 adb->keys->push_back(datum->key);
|
mas01cr@453
|
202 (*adb->keymap)[datum->key] = adb->header->numFiles;
|
mas01cr@432
|
203 adb->track_lengths->push_back(datum->nvectors);
|
mas01cr@453
|
204 adb->track_offsets->push_back(offset);
|
mas01cr@404
|
205 adb->header->numFiles += 1;
|
mas01cr@404
|
206 adb->header->length += sizeof(double) * datum->nvectors * datum->dim;
|
mas01cr@404
|
207
|
mas01cr@409
|
208 /* 9. sync adb->header with disk. */
|
mas01cr@404
|
209 return audiodb_sync_header(adb);
|
mas01cr@404
|
210
|
mas01cr@404
|
211 error:
|
mas01cr@410
|
212 if(l2norm_buffer) {
|
mas01cr@410
|
213 free(l2norm_buffer);
|
mas01cr@410
|
214 }
|
mas01cr@404
|
215 return 1;
|
mas01cr@404
|
216 }
|
mas01cr@239
|
217
|
mas01cr@473
|
218 int audiodb_insert_datum(adb_t *adb, const adb_datum_t *datum) {
|
mas01cr@440
|
219 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
|
mas01cr@440
|
220 return 1;
|
mas01cr@440
|
221 } else {
|
mas01cr@440
|
222 adb_datum_internal_t d;
|
mas01cr@440
|
223 d.nvectors = datum->nvectors;
|
mas01cr@440
|
224 d.dim = datum->dim;
|
mas01cr@440
|
225 d.key = datum->key;
|
mas01cr@440
|
226 d.data = datum->data;
|
mas01cr@440
|
227 d.times = datum->times;
|
mas01cr@440
|
228 d.power = datum->power;
|
mas01cr@440
|
229 return audiodb_insert_datum_internal(adb, &d);
|
mas01cr@440
|
230 }
|
mas01cr@408
|
231 }
|
mas01cr@408
|
232
|
mas01cr@473
|
233 int audiodb_insert_reference(adb_t *adb, const adb_reference_t *reference) {
|
mas01cr@441
|
234 if(!(adb->header->flags & O2_FLAG_LARGE_ADB)) {
|
mas01cr@441
|
235 return 1;
|
mas01cr@441
|
236 } else {
|
mas01cr@441
|
237 adb_datum_internal_t d;
|
mas01cr@441
|
238 struct stat st;
|
mas01cr@441
|
239 int fd;
|
mas01cr@441
|
240 off_t size;
|
mas01cr@441
|
241
|
mas01cr@441
|
242 if((fd = open(reference->features, O_RDONLY)) == -1) {
|
mas01cr@441
|
243 return 1;
|
mas01cr@441
|
244 }
|
mas01cr@441
|
245 if(fstat(fd, &st)) {
|
mas01cr@441
|
246 goto error;
|
mas01cr@441
|
247 }
|
mas01cr@441
|
248 read_or_goto_error(fd, &(d.dim), sizeof(uint32_t));
|
mas01cr@441
|
249 close(fd);
|
mas01cr@441
|
250 fd = 0;
|
mas01cr@441
|
251 size = st.st_size - sizeof(uint32_t);
|
mas01cr@441
|
252 d.nvectors = size / (sizeof(double) * d.dim);
|
mas01cr@441
|
253 d.data = (void *) reference->features;
|
mas01cr@441
|
254 if(reference->power) {
|
mas01cr@441
|
255 if(stat(reference->power, &st)) {
|
mas01cr@441
|
256 return 1;
|
mas01cr@441
|
257 }
|
mas01cr@441
|
258 }
|
mas01cr@441
|
259 d.power = (void *) reference->power;
|
mas01cr@441
|
260 if(reference->times) {
|
mas01cr@441
|
261 if(stat(reference->times, &st)) {
|
mas01cr@441
|
262 return 1;
|
mas01cr@441
|
263 }
|
mas01cr@441
|
264 }
|
mas01cr@441
|
265 d.times = (void *) reference->times;
|
mas01cr@441
|
266 d.key = reference->key ? reference->key : reference->features;
|
mas01cr@441
|
267 return audiodb_insert_datum_internal(adb, &d);
|
mas01cr@441
|
268 error:
|
mas01cr@441
|
269 if(fd) {
|
mas01cr@441
|
270 close(fd);
|
mas01cr@441
|
271 }
|
mas01cr@441
|
272 return 1;
|
mas01cr@441
|
273 }
|
mas01cr@441
|
274 }
|
mas01cr@441
|
275
|
mas01cr@443
|
276 int audiodb_free_datum(adb_datum_t *datum) {
|
mas01cr@406
|
277 if(datum->data) {
|
mas01cr@406
|
278 free(datum->data);
|
mas01cr@472
|
279 datum->data = NULL;
|
mas01cr@406
|
280 }
|
mas01cr@406
|
281 if(datum->power) {
|
mas01cr@406
|
282 free(datum->power);
|
mas01cr@472
|
283 datum->power = NULL;
|
mas01cr@406
|
284 }
|
mas01cr@406
|
285 if(datum->times) {
|
mas01cr@406
|
286 free(datum->times);
|
mas01cr@472
|
287 datum->times = NULL;
|
mas01cr@406
|
288 }
|
mas01cr@406
|
289 return 0;
|
mas01cr@406
|
290 }
|
mas01cr@406
|
291
|
mas01cr@443
|
292 int audiodb_insert_create_datum(adb_insert_t *insert, adb_datum_t *datum) {
|
mas01cr@405
|
293 int fd = 0;
|
mas01cr@405
|
294 FILE *file = NULL;
|
mas01cr@405
|
295 struct stat st;
|
mas01cr@404
|
296 off_t size;
|
mas01cr@405
|
297
|
mas01cr@406
|
298 datum->data = NULL;
|
mas01cr@406
|
299 datum->power = NULL;
|
mas01cr@406
|
300 datum->times = NULL;
|
mas01cr@405
|
301 if((fd = open(insert->features, O_RDONLY)) == -1) {
|
mas01cr@405
|
302 goto error;
|
mas01cr@370
|
303 }
|
mas01cr@405
|
304 if(fstat(fd, &st)) {
|
mas01cr@405
|
305 goto error;
|
mas01cr@404
|
306 }
|
mas01cr@410
|
307 read_or_goto_error(fd, &(datum->dim), sizeof(uint32_t));
|
mas01cr@405
|
308 size = st.st_size - sizeof(uint32_t);
|
mas01cr@406
|
309 datum->nvectors = size / (sizeof(double) * datum->dim);
|
mas01cr@406
|
310 datum->data = (double *) malloc(size);
|
mas01cr@406
|
311 if(!datum->data) {
|
mas01cr@405
|
312 goto error;
|
mas01cr@404
|
313 }
|
mas01cr@410
|
314 read_or_goto_error(fd, datum->data, size);
|
mas01cr@404
|
315 close(fd);
|
mas01cr@405
|
316 fd = 0;
|
mas01cr@405
|
317 if(insert->power) {
|
mas01cr@405
|
318 int dim;
|
mas01cr@405
|
319 if((fd = open(insert->power, O_RDONLY)) == -1) {
|
mas01cr@405
|
320 goto error;
|
mas01cr@405
|
321 }
|
mas01cr@405
|
322 if(fstat(fd, &st)) {
|
mas01cr@405
|
323 goto error;
|
mas01cr@405
|
324 }
|
mas01cr@412
|
325 /* This cast is so non-trivial that it deserves a comment.
|
mas01cr@412
|
326 *
|
mas01cr@412
|
327 * The data types in this expression, left to right, are: off_t,
|
mas01cr@412
|
328 * size_t, off_t, uint32_t. The rules for conversions in
|
mas01cr@412
|
329 * arithmetic expressions with mixtures of integral types are
|
mas01cr@412
|
330 * essentially that the widest type wins, with unsigned types
|
mas01cr@412
|
331 * winning on a tie-break.
|
mas01cr@412
|
332 *
|
mas01cr@412
|
333 * Because we are enforcing (through the use of sufficient
|
mas01cr@412
|
334 * compiler flags, if necessary) that off_t be a (signed) 64-bit
|
mas01cr@412
|
335 * type, the only variability in this set of types is in fact the
|
mas01cr@412
|
336 * size_t. On 32-bit machines, size_t is uint32_t and so the
|
mas01cr@412
|
337 * coercions on both sides of the equality end up promoting
|
mas01cr@412
|
338 * everything to int64_t, which is fine. On 64-bit machines,
|
mas01cr@412
|
339 * however, the left hand side is promoted to a uint64_t, while
|
mas01cr@412
|
340 * the right hand side remains int64_t.
|
mas01cr@412
|
341 *
|
mas01cr@412
|
342 * The mixture of signed and unsigned types in comparisons is Evil
|
mas01cr@412
|
343 * Bad and Wrong, and gcc complains about it. (It's right to do
|
mas01cr@412
|
344 * so, actually). Of course in this case it will never matter
|
mas01cr@412
|
345 * because of the particular relationships between all of these
|
mas01cr@412
|
346 * numbers, so we just cast the left hand side to off_t, which
|
mas01cr@412
|
347 * will do the right thing for us on all platforms.
|
mas01cr@412
|
348 *
|
mas01cr@412
|
349 * I hate C.
|
mas01cr@412
|
350 */
|
mas01cr@412
|
351 if(((off_t) (st.st_size - sizeof(uint32_t))) != (size / datum->dim)) {
|
mas01cr@405
|
352 goto error;
|
mas01cr@405
|
353 }
|
mas01cr@410
|
354 read_or_goto_error(fd, &dim, sizeof(uint32_t));
|
mas01cr@405
|
355 if(dim != 1) {
|
mas01cr@405
|
356 goto error;
|
mas01cr@405
|
357 }
|
mas01cr@406
|
358 datum->power = (double *) malloc(size / datum->dim);
|
mas01cr@406
|
359 if(!datum->power) {
|
mas01cr@405
|
360 goto error;
|
mas01cr@405
|
361 }
|
mas01cr@410
|
362 read_or_goto_error(fd, datum->power, size / datum->dim);
|
mas01cr@405
|
363 close(fd);
|
mas01cr@405
|
364 }
|
mas01cr@405
|
365 if(insert->times) {
|
mas01cr@405
|
366 double t, *tp;
|
mas01cr@405
|
367 if(!(file = fopen(insert->times, "r"))) {
|
mas01cr@405
|
368 goto error;
|
mas01cr@405
|
369 }
|
mas01cr@406
|
370 datum->times = (double *) malloc(2 * size / datum->dim);
|
mas01cr@406
|
371 if(!datum->times) {
|
mas01cr@405
|
372 goto error;
|
mas01cr@404
|
373 }
|
mas01cr@405
|
374 if(fscanf(file, " %lf", &t) != 1) {
|
mas01cr@405
|
375 goto error;
|
mas01cr@405
|
376 }
|
mas01cr@406
|
377 tp = datum->times;
|
mas01cr@405
|
378 *tp++ = t;
|
mas01cr@406
|
379 for(unsigned int n = 0; n < datum->nvectors - 1; n++) {
|
mas01cr@405
|
380 if(fscanf(file, " %lf", &t) != 1) {
|
mas01cr@405
|
381 goto error;
|
mas01cr@405
|
382 }
|
mas01cr@405
|
383 *tp++ = t;
|
mas01cr@405
|
384 *tp++ = t;
|
mas01cr@405
|
385 }
|
mas01cr@405
|
386 if(fscanf(file, " %lf", &t) != 1) {
|
mas01cr@405
|
387 goto error;
|
mas01cr@405
|
388 }
|
mas01cr@405
|
389 *tp = t;
|
mas01cr@405
|
390 fclose(file);
|
mas01cr@404
|
391 }
|
mas01cr@406
|
392 datum->key = insert->key ? insert->key : insert->features;
|
mas01cr@406
|
393 return 0;
|
mas01cr@405
|
394
|
mas01cr@405
|
395 error:
|
mas01cr@405
|
396 if(fd > 0) {
|
mas01cr@405
|
397 close(fd);
|
mas01cr@405
|
398 }
|
mas01cr@405
|
399 if(file) {
|
mas01cr@405
|
400 fclose(file);
|
mas01cr@405
|
401 }
|
mas01cr@406
|
402 audiodb_free_datum(datum);
|
mas01cr@406
|
403 return 1;
|
mas01cr@406
|
404 }
|
mas01cr@406
|
405
|
mas01cr@406
|
406 int audiodb_insert(adb_t *adb, adb_insert_t *insert) {
|
mas01cr@406
|
407 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
|
mas01cr@441
|
408 adb_reference_t *reference = insert;
|
mas01cr@409
|
409 int err;
|
mas01cr@441
|
410 err = audiodb_insert_reference(adb, reference);
|
mas01cr@409
|
411
|
mas01cr@409
|
412 if(err == 2) {
|
mas01cr@409
|
413 return 0;
|
mas01cr@409
|
414 } else {
|
mas01cr@409
|
415 return err;
|
mas01cr@409
|
416 }
|
mas01cr@406
|
417 } else {
|
mas01cr@406
|
418 adb_datum_t datum;
|
mas01cr@406
|
419 int err;
|
mas01cr@406
|
420
|
mas01cr@406
|
421 if(audiodb_insert_create_datum(insert, &datum)) {
|
mas01cr@406
|
422 return 1;
|
mas01cr@406
|
423 }
|
mas01cr@406
|
424 err = audiodb_insert_datum(adb, &datum);
|
mas01cr@406
|
425 audiodb_free_datum(&datum);
|
mas01cr@406
|
426
|
mas01cr@406
|
427 if(err == 2) {
|
mas01cr@406
|
428 return 0;
|
mas01cr@409
|
429 } else {
|
mas01cr@406
|
430 return err;
|
mas01cr@406
|
431 }
|
mas01cr@405
|
432 }
|
mas01cr@405
|
433 }
|
mas01cr@405
|
434
|
mas01cr@405
|
435 int audiodb_batchinsert(adb_t *adb, adb_insert_t *insert, unsigned int size) {
|
mas01cr@405
|
436 int err;
|
mas01cr@405
|
437 for(unsigned int n = 0; n < size; n++) {
|
mas01cr@405
|
438 if((err = audiodb_insert(adb, &(insert[n])))) {
|
mas01cr@405
|
439 return err;
|
mas01cr@404
|
440 }
|
mas01cr@404
|
441 }
|
mas01cr@405
|
442 return 0;
|
mas01cr@239
|
443 }
|