OSDN Git Service

add residhash wrapper to datcache.
[bbk/bchan.git] / src / cache.c
1 /*
2  * cache.c
3  *
4  * Copyright (c) 2009-2010 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include        <basic.h>
28 #include        <bstdlib.h>
29 #include        <bstdio.h>
30 #include        <bstring.h>
31 #include        <errcode.h>
32 #include        <btron/btron.h>
33 #include        <bsys/queue.h>
34
35 #include    "cache.h"
36 #include    "residhash.h"
37
38 typedef struct datcache_data_t_ datcache_data_t;
39
40 struct datcache_data_t_ {
41         QUEUE queue;
42         UB *data;
43         W len;
44 };
45
46 struct datcache_t_ {
47         W fd;
48         ID semid;
49         datcache_data_t datalist;
50         W s_datsize;
51         datcache_datareadcontext_t *context;
52         UB *retrinfo;
53         W retrinfo_len;
54         UB *host;
55         W host_len;
56         UB *board;
57         W board_len;
58         UB *thread;
59         W thread_len;
60         UB *latestheader;
61         W latestheader_len;
62         residhash_t residhash;
63 };
64
65 struct datcache_datareadcontext_t_ {
66         datcache_t *datcache;
67         datcache_data_t *current;
68         W index;
69 };
70
71 LOCAL datcache_data_t* datcache_data_next(datcache_data_t *data)
72 {
73         return (datcache_data_t*)data->queue.next;
74 }
75
76 LOCAL datcache_data_t* datcache_data_new(UB *data, W len)
77 {
78         datcache_data_t *cache_data;
79
80         cache_data = malloc(sizeof(datcache_data_t));
81         if (cache_data == NULL) {
82                 return NULL;
83         }
84         cache_data->data = malloc(sizeof(UB)*len);
85         if (cache_data->data == NULL) {
86                 free(cache_data);
87                 return NULL;
88         }
89         memcpy(cache_data->data, data, len);
90         cache_data->len = len;
91
92         return cache_data;
93 }
94
95 LOCAL VOID datcache_data_delete(datcache_data_t *cache_data)
96 {
97         QueRemove(&(cache_data->queue));
98         if (cache_data->data != NULL) {
99                 free(cache_data->data);
100         }
101         free(cache_data);
102 }
103
104 EXPORT W datcache_appenddata(datcache_t *cache, UB *data, W len)
105 {
106         datcache_data_t *cache_data;
107         W err;
108
109         err = wai_sem(cache->semid, T_FOREVER);
110         if (err < 0) {
111                 return err;
112         }
113
114         if (cache->context != NULL) {
115                 sig_sem(cache->semid);
116                 return -1;
117         }
118
119         cache_data = datcache_data_new(data, len);
120         if (cache_data == NULL) {
121                 sig_sem(cache->semid);
122                 return -1; /* TODO */
123         }
124         QueInsert(&(cache_data->queue), &(cache->datalist.queue));
125         cache->s_datsize += len;
126
127         sig_sem(cache->semid);
128         return 0; /* TODO */
129 }
130
131 EXPORT VOID datcache_cleardata(datcache_t *cache)
132 {
133         datcache_data_t *cache_data;
134         Bool ok;
135         W err;
136
137         err = wai_sem(cache->semid, T_FOREVER);
138         if (err < 0) {
139                 return;
140         }
141
142         if (cache->context != NULL) {
143                 sig_sem(cache->semid);
144                 return;
145         }
146
147         for (;;) {
148                 ok = isQueEmpty(&(cache->datalist.queue));
149                 if (ok == True) {
150                         break;
151                 }
152                 cache_data = (datcache_data_t*)cache->datalist.queue.next;
153                 datcache_data_delete(cache_data);
154         }
155         free(cache->datalist.data);
156
157         cache->datalist.data = NULL;
158         cache->datalist.len = 0;
159         cache->s_datsize = 0;
160
161         sig_sem(cache->semid);
162 }
163
164 EXPORT Bool datcache_datareadcontext_nextdata(datcache_datareadcontext_t *context, UB **bin, W *len)
165 {
166         datcache_data_t *next;
167
168         if (context->current == NULL) {
169                 return False;
170         }
171
172         *bin = context->current->data + context->index;
173         *len = context->current->len - context->index;
174
175         next = datcache_data_next(context->current);
176         if (next == &(context->datcache->datalist)) {
177                 next = NULL;
178         }
179         context->current = next;
180         context->index = 0;
181
182         return True;
183 }
184
185 LOCAL datcache_datareadcontext_t* datcache_datareadcontext_new(datcache_t *cache)
186 {
187         datcache_datareadcontext_t *context;
188
189         context = malloc(sizeof(datcache_datareadcontext_t*));
190         if (context == NULL) {
191                 return NULL;
192         }
193         context->datcache = cache;
194
195         return context;
196 }
197
198 LOCAL VOID datcache_datareadcontext_delete(datcache_datareadcontext_t *context)
199 {
200         free(context);
201 }
202
203 EXPORT datcache_datareadcontext_t* datcache_startdataread(datcache_t *cache, W start)
204 {
205         datcache_datareadcontext_t *context;
206         datcache_data_t *cache_data;
207         W err,dest;
208
209         err = wai_sem(cache->semid, T_FOREVER);
210         if (err < 0) {
211                 return NULL;
212         }
213
214         if (cache->context != NULL) {
215                 sig_sem(cache->semid);
216                 return NULL;
217         }
218
219         context = datcache_datareadcontext_new(cache);
220         if (context == NULL) {
221                 return NULL;
222         }
223         cache->context = context;
224
225         if (start >= cache->s_datsize) {
226                 context->current = NULL;
227                 context->index = 0;
228                 return context;
229         }
230
231         cache_data = &(cache->datalist);
232         dest = start;
233         for (;;) {
234                 if (dest < cache_data->len) {
235                         break;
236                 }
237                 dest -= cache_data->len;
238                 cache_data = datcache_data_next(cache_data);
239         }
240
241         context->current = cache_data;
242         context->index = dest;
243
244         return context;
245 }
246
247 EXPORT VOID datcache_enddataread(datcache_t *cache, datcache_datareadcontext_t *context)
248 {
249         cache->context = NULL;
250         datcache_datareadcontext_delete(context);
251
252         sig_sem(cache->semid);
253 }
254
255 EXPORT VOID datcache_getlatestheader(datcache_t *cache, UB **header, W *len)
256 {
257         *header = cache->latestheader;
258         *len = cache->latestheader_len;
259 }
260
261 EXPORT W datcache_updatelatestheader(datcache_t *cache, UB *header, W len)
262 {
263         UB *latestheader0;
264
265         latestheader0 = realloc(cache->latestheader, len + 1);
266         if (latestheader0 == NULL) {
267                 return -1;
268         }
269
270         cache->latestheader = latestheader0;
271         memcpy(cache->latestheader, header, len);
272         cache->latestheader_len = len;
273         cache->latestheader[cache->latestheader_len] = '\0';
274
275         return 0;
276 }
277
278 EXPORT VOID datcache_gethost(datcache_t *cache, UB **host, W *len)
279 {
280         *host = cache->host;
281         *len = cache->host_len;
282 }
283
284 EXPORT VOID datcache_getborad(datcache_t *cache, UB **borad, W *len)
285 {
286         *borad = cache->board;
287         *len = cache->board_len;
288 }
289
290 EXPORT VOID datcache_getthread(datcache_t *cache, UB **thread, W *len)
291 {
292         *thread = cache->thread;
293         *len = cache->thread_len;
294 }
295
296 LOCAL VOID datcache_setupretrinfo(datcache_t *cache, UB *retrinfo, W len)
297 {
298         W i=0;
299
300         cache->retrinfo = retrinfo;
301         cache->retrinfo_len = len;
302         cache->host = NULL;
303         cache->host_len = 0;
304         cache->board = NULL;
305         cache->board_len = 0;
306         cache->thread = NULL;
307         cache->thread_len = 0;
308
309         if (cache->retrinfo == NULL) {
310                 return;
311         }
312
313         cache->host = cache->retrinfo;
314         for (; i < len; i++) {
315                 if (cache->retrinfo[i] == '\n') {
316                         break;
317                 }
318                 cache->host_len++;
319         }
320
321         i++;
322         cache->board = cache->retrinfo + i;
323         for (; i < len; i++) {
324                 if (cache->retrinfo[i] == '\n') {
325                         break;
326                 }
327                 cache->board_len++;
328         }
329
330         i++;
331         cache->thread = cache->retrinfo + i;
332         for (; i < len; i++) {
333                 if (cache->retrinfo[i] == '\n') {
334                         break;
335                 }
336                 cache->thread_len++;
337         }
338 }
339
340 LOCAL W datcache_preparerec_forwritefile(W fd, W rectype, W subtype)
341 {
342         W err;
343
344         err = fnd_rec(fd, F_TOPEND, 1 << rectype, subtype, NULL);
345         if (err == ER_REC) {
346                 err = ins_rec(fd, NULL, 0, rectype, subtype, 0);
347                 if (err < 0) {
348                         return -1;
349                 }
350                 err = see_rec(fd, -1, 0, NULL);
351                 if (err < 0) {
352                         return -1;
353                 }
354         } else if (err < 0) {
355                 return -1; /* TODO */
356         } else {
357                 err = trc_rec(fd, 0);
358                 if (err < 0) {
359                         return -1;
360                 }
361         }
362
363         return 0; /* TODO */
364 }
365
366 EXPORT W datcache_datasize(datcache_t *cache)
367 {
368         return cache->s_datsize;
369 }
370
371 EXPORT W datcache_writefile(datcache_t *cache)
372 {
373         W err;
374         datcache_data_t *cache_data;
375
376         /* TODO: blush up implementation for speed up. */
377         if (cache->s_datsize > 0) {
378                 err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_MAIN, 0);
379                 if (err < 0) {
380                         return err;
381                 }
382                 cache_data = &(cache->datalist);
383                 for (;;) {
384                         err = wri_rec(cache->fd, -1, cache_data->data, cache_data->len, NULL, NULL, 0);
385                         if (err < 0) {
386                                 return err;
387                         }
388                         cache_data = datcache_data_next(cache_data);
389                         if (cache_data == &(cache->datalist)) {
390                                 break;
391                         }
392                 }
393         }
394
395         if (cache->latestheader_len > 0) {
396                 err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_HEADER);
397                 if (err < 0) {
398                         return err;
399                 }
400                 err = wri_rec(cache->fd, -1, cache->latestheader, cache->latestheader_len, NULL, NULL, 0);
401                 if (err < 0) {
402                         return err;
403                 }
404         }
405
406         return 0;
407 }
408
409 EXPORT W datcache_addresiddata(datcache_t *cache, TC *idstr, W idstr_len, UW attr, COLOR color)
410 {
411         return residhash_adddata(&cache->residhash, idstr, idstr_len, attr, color);
412 }
413
414 EXPORT W datcache_searchresiddata(datcache_t *cache, TC *idstr, W idstr_len, UW *attr, COLOR *color)
415 {
416         return residhash_searchdata(&cache->residhash, idstr, idstr_len, attr, color);
417 }
418
419 EXPORT VOID datcache_removeresiddata(datcache_t *cache, TC *idstr, W idstr_len)
420 {
421         residhash_removedata(&cache->residhash, idstr, idstr_len);
422 }
423
424 LOCAL W datcache_getrec_fromfile(W fd, W rectype, W subtype, UB **data, W *size)
425 {
426         W err, size0;
427         UB *data0;
428
429         err = fnd_rec(fd, F_TOPEND, 1 << rectype, subtype, NULL);
430         if (err == ER_REC) {
431                 *data = NULL;
432                 *size = 0;
433                 return 0;
434         }
435         if (err < 0) {
436                 return -1; /* TODO */
437         }
438         err = rea_rec(fd, 0, NULL, 0, &size0, NULL);
439         if (err < 0) {
440                 return -1; /* TODO */
441         }
442         if (size0 == 0) {
443                 *data = NULL;
444                 *size = 0;
445                 return 0;
446         }
447         data0 = malloc(size0);
448         if (data0 == NULL) {
449                 return -1; /* TODO */
450         }
451         err = rea_rec(fd, 0, data0, size0, NULL, NULL);
452         if (err < 0) {
453                 free(data0);
454                 return -1; /* TODO */
455         }
456
457         *data = data0;
458         *size = size0;
459
460         return 0;
461 }
462
463 LOCAL W datcache_getdat_fromfile(W fd, UB **data, W *size)
464 {
465         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_MAIN, 0, data, size);
466 }
467
468 LOCAL W datcache_getretrinfo_fromfile(W fd, UB **data, W *size)
469 {
470         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RETRIEVE, data, size);
471 }
472
473 LOCAL W datcache_getheader_fromfile(W fd, UB **data, W *size)
474 {
475         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_HEADER, data, size);
476 }
477
478 EXPORT datcache_t* datcache_new(VID vid)
479 {
480         datcache_t *cache;
481         ID semid;
482         W fd,err;
483         W size, retrinfo_len, header_len;
484         UB *rawdat, *retrinfo, *header;
485
486         fd = oopn_obj(vid, NULL, F_READ|F_WRITE, NULL);
487         if (fd < 0) {
488                 return NULL;
489         }
490         semid = cre_sem(1, SEM_EXCL|DELEXIT);
491         if (semid < 0) {
492                 cls_fil(fd);
493                 return NULL;
494         }
495         err = datcache_getdat_fromfile(fd, &rawdat, &size);
496         if (err < 0) {
497                 del_sem(semid);
498                 cls_fil(fd);
499                 return NULL;
500         }
501         err = datcache_getretrinfo_fromfile(fd, &retrinfo, &retrinfo_len);
502         if (err < 0) {
503                 if (rawdat != NULL) {
504                         free(rawdat);
505                 }
506                 del_sem(semid);
507                 cls_fil(fd);
508                 return NULL;
509         }
510         err = datcache_getheader_fromfile(fd, &header, &header_len);
511         if (err < 0) {
512                 if (retrinfo != NULL) {
513                         free(retrinfo);
514                 }
515                 if (rawdat != NULL) {
516                         free(rawdat);
517                 }
518                 del_sem(semid);
519                 cls_fil(fd);
520                 return NULL;
521         }
522
523         cache = (datcache_t*)malloc(sizeof(datcache_t));
524         if (cache == NULL) {
525                 free(retrinfo);
526                 free(rawdat);
527                 del_sem(semid);
528                 cls_fil(fd);
529                 return NULL;
530         }
531         cache->fd = fd;
532         cache->semid = semid;
533         QueInit(&(cache->datalist.queue));
534         cache->datalist.data = rawdat;
535         cache->datalist.len = size;
536         cache->s_datsize = size;
537         cache->context = NULL;
538
539         datcache_setupretrinfo(cache, retrinfo, retrinfo_len);
540         cache->latestheader = header;
541         cache->latestheader_len = header_len;
542
543         err = residhash_initialize(&cache->residhash);
544         if (err < 0) {
545                 free(retrinfo);
546                 free(rawdat);
547                 del_sem(semid);
548                 cls_fil(fd);
549                 free(cache);
550                 return NULL;
551         }
552
553         return cache;
554 }
555
556 EXPORT VOID datcache_delete(datcache_t *cache)
557 {
558         datcache_data_t *cache_data;
559         Bool ok;
560
561         residhash_finalize(&cache->residhash);
562
563         if (cache->latestheader != NULL) {
564                 free(cache->latestheader);
565         }
566         if (cache->retrinfo != NULL) {
567                 free(cache->retrinfo);
568         }
569
570         for (;;) {
571                 ok = isQueEmpty(&(cache->datalist.queue));
572                 if (ok == True) {
573                         break;
574                 }
575                 cache_data = datcache_data_next(&cache->datalist);
576                 datcache_data_delete(cache_data);
577         }
578         free(cache->datalist.data);
579         del_sem(cache->semid);
580         cls_fil(cache->fd);
581         free(cache);
582 }