source: svn/trunk/newcon3bcm2_21bu/dta/src/bfdb/bfdb.c @ 2

Last change on this file since 2 was 2, checked in by phkim, 11 years ago

1.phkim

  1. revision copy newcon3sk r27
  • Property svn:executable set to *
File size: 24.0 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2010, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: $
11 * $brcm_Revision: $
12 * $brcm_Date: $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: $
19 *
20 *
21 ***************************************************************************/
22
23#include "bstd.h"
24#include "bkni.h"
25#include "bdbg.h"
26
27#include "bfdb.h"
28
29BDBG_MODULE(bfdb);
30
31#define BFDB_MAGIC 0xBFDBBABE
32
33#define BFDB_TUPLE_HEAD_SIZE 2
34#define BFDB_LOG_SIZE 8
35/*
36   Number of reserved sectors used to move records before erasing
37   empty space. More reseved sectors would allow to reclaim more space and
38   faster operation. At least one sector must be reserved.
39 */
40#define BFDB_RESERVED_SECTORS 1
41
42#define BFDB_PAGE_OVERLAP 0x10
43
44/* Log flags definitions. These define bit positions since actual flags have
45   value of 0 when set and 1 when not set due to the properties of flash */
46#define BFDB_LF_LOG_START 1
47
48struct bfdb_log {
49        uint8_t flags;
50        uint8_t dummy;
51        uint32_t checksum;
52} __attribute__((packed));
53
54enum bfdb_rec_state_t {
55        brs_start,
56        brs_id,
57        brs_size,
58        brs_data,
59        brs_data2
60};
61
62static struct bfdb_state dbs;
63
64static void bfdb_tuple_put_head( void * buf, uint8_t id, uint8_t size );
65static bfdb_err bfdb_db_load(bfdb_handle handle);
66static bfdb_err bfdb_db_load_log(bfdb_handle handle, uint32_t offset);
67static uint32_t bfdb_tuple_get_size(void * tuple);
68static uint32_t bfdb_tuple_get_id(void * tuple);
69static bfdb_err bfdb_log_walk(bfdb_handle handle, uint32_t start, uint8_t id);
70static bfdb_err bfdb_log_add(bfdb_handle handle, uint8_t * tuple, size_t tsize);
71static bfdb_err bfdb_log_pad_sector(bfdb_handle handle, size_t * padded_size);
72static bfdb_err bfdb_log_open_sector(bfdb_handle handle);
73static uint32_t bfdb_mod_sum(uint32_t sum, uint8_t * data, size_t dsize);
74
75bfdb_err bfdb_open(struct bfdb_settings * settings, bfdb_handle * handle)
76{
77        bfdb_err dberr;
78
79        BDBG_ASSERT(NULL != settings);
80        BKNI_Memset(&dbs, 0, sizeof(struct bfdb_state));
81        /* check parameters for consistency */
82        if(0 != (settings->db_offset % settings->sector_size)){
83                dberr = BFDB_INVALID_PARAMETER;
84                goto ExitFunc;
85        }
86        if(0 != (settings->db_size % settings->sector_size)){
87                dberr = BFDB_INVALID_PARAMETER;
88                goto ExitFunc;
89        }
90        dbs.magic = BFDB_MAGIC;
91        dbs.page_size = settings->page_size;
92        dbs.sector_size = settings->sector_size;
93        dbs.fl_start = settings->db_offset;
94        dbs.fl_end = settings->db_offset + settings->db_size;
95       
96        dberr = bfds_open(&dbs.store);
97        if(BFDS_OK != dberr){
98                dberr = BFDB_STORE_ERROR;
99                goto ExitFunc;
100        }
101
102        dbs.pb_size = dbs.page_size * 2;
103        dbs.page_buffer = BKNI_Malloc(dbs.pb_size+BFDB_PAGE_OVERLAP);
104        if(NULL == dbs.page_buffer){
105                dberr = BFDB_INTERNAL_ERROR;
106                goto ExitFunc;
107        }
108        dbs.page_buffer2 = BKNI_Malloc(dbs.pb_size+BFDB_PAGE_OVERLAP);
109        if(NULL == dbs.page_buffer2){
110                dberr = BFDB_INTERNAL_ERROR;
111                BKNI_Free(dbs.page_buffer);
112                goto ExitFunc;
113        }
114
115        dberr = bfdb_db_load(&dbs);
116
117        *handle = &dbs;
118ExitFunc:
119        return dberr;
120}
121
122bfdb_err bfdb_rewind(bfdb_handle handle, uint8_t id)
123{
124        return bfdb_log_walk(handle, handle->db_head, id);
125}
126
127bfdb_err bfdb_next(bfdb_handle handle, uint8_t id)
128{
129        bfdb_err dberr;
130
131        uint8_t * tuple;
132        size_t tu_size;
133
134        tuple = handle->page_buffer;
135
136        dberr = bfds_read(handle->store, handle->cursor, handle->page_buffer, BFDB_TUPLE_HEAD_SIZE);
137        if(0 != dberr){
138                dberr = BFDB_STORE_ERROR;
139                goto ExitFunc;
140        }
141        tu_size = BFDB_TUPLE_HEAD_SIZE + bfdb_tuple_get_size(tuple);
142        /* look for required id starting with next tuple */
143        dberr = bfdb_log_walk(handle, handle->cursor + tu_size, id);
144ExitFunc:
145        return dberr;
146}
147
148bfdb_err bfdb_get(bfdb_handle handle, uint8_t * data, size_t size)
149{
150        bfdb_err dberr;
151        size_t tu_size;
152        dberr = bfds_read(handle->store, handle->cursor, handle->page_buffer, BFDB_TUPLE_HEAD_SIZE);
153        if(0 != dberr){
154                dberr = BFDB_STORE_ERROR;
155                goto ExitFunc;
156        }
157        tu_size = bfdb_tuple_get_size(handle->page_buffer);
158        if(size < tu_size){
159                tu_size = size;
160        }
161
162        if (tu_size == 0)
163        {
164                dberr = BFDB_STORE_ERROR;
165                goto ExitFunc;
166        }
167        dberr = bfds_read(handle->store, handle->cursor+BFDB_TUPLE_HEAD_SIZE, data, tu_size);
168        if(0 != dberr){
169                dberr = BFDB_STORE_ERROR;
170        }
171ExitFunc:
172        return dberr;
173}
174
175/*
176  Start writing from db_tail and write up to amount of data in the tuple.
177  We may have to execute 2 page program operation is data spans across 2 pages.
178 */
179bfdb_err bfdb_add(bfdb_handle handle, uint8_t id, uint8_t * data, size_t size)
180{
181        uint32_t o_size;
182        uint32_t sector_mask;
183        uint32_t empty_size;
184        bfdb_err dberr;
185
186        sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */
187
188        /* check if database is full before adding any more data */
189        if(handle->db_head < handle->db_tail){
190                empty_size = handle->fl_end - handle->db_tail + handle->db_head - handle->fl_start;
191        }else{
192                empty_size = handle->db_head - handle->db_tail;
193        }
194        if(empty_size <= BFDB_RESERVED_SECTORS * handle->sector_size){
195                dberr = BFDB_LOG_FULL;
196                goto ExitFunc;
197        }
198
199        /* check if new write will cros sector boundary including extra log tuple */
200        o_size = (handle->db_tail & sector_mask) + BFDB_TUPLE_HEAD_SIZE + size + BFDB_LOG_SIZE;
201        if(0 < (o_size & (~sector_mask))){
202                BDBG_ASSERT((BFDB_DATA_MAX+BFDB_TUPLE_HEAD_SIZE) <= o_size);
203                dberr = bfdb_log_pad_sector(handle, &o_size);
204                if(0 != dberr){
205                        goto ExitFunc;
206                }
207                /* update empty space size computed earlier and check if log is full */
208                empty_size -= o_size;
209                if(empty_size <= BFDB_RESERVED_SECTORS * handle->sector_size){
210                        dberr = BFDB_LOG_FULL;
211                        goto ExitFunc;
212                }
213        }
214        if(0 == (handle->db_tail & sector_mask)){
215                /* if we are on the sector boundary write log tuple */
216                dberr = bfdb_log_open_sector(handle);
217                if(0 != dberr){
218                        goto ExitFunc;
219                }
220        }
221        /* form tuple from the data */
222        bfdb_tuple_put_head(handle->page_buffer, id, size);
223        BKNI_Memcpy(&(handle->page_buffer[BFDB_TUPLE_HEAD_SIZE]), data, size);
224        handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, data, size);
225        dberr = bfdb_log_add(handle, handle->page_buffer, (BFDB_TUPLE_HEAD_SIZE + size));
226ExitFunc:
227        return dberr;
228}
229
230bfdb_err bfdb_delete(bfdb_handle handle)
231{
232        bfdb_err dberr;
233        uint32_t small_buffer;
234        small_buffer = BFDB_TUPLE_ERASED;
235        dberr = bfds_page_program(handle->store, handle->cursor, &small_buffer, 1);
236        if(0 != dberr){
237                dberr = BFDB_STORE_ERROR;
238        }
239        return dberr;
240}
241
242/**
243   Starting from the beginning of the log find all non erased and non log
244   tuples. Move them one by one to the end of the log. After sector is free,
245   mark next sector as beginning of the log and erase the sector.
246 */
247bfdb_err bfdb_compact(bfdb_handle handle)
248{
249        bfdb_err dberr;
250        uint8_t * pb_walker;
251        size_t tu_size;
252        uint8_t tu_id;
253        uint32_t page_mask;
254        uint32_t page_addr;
255        uint32_t sector_mask;
256        uint32_t o_size;
257        uint32_t moved_size, erased_size;
258       
259
260        page_mask = handle->pb_size - 1; /* pb_size must be pow of 2 */
261        sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */
262        page_addr = handle->db_head & ~page_mask;
263        pb_walker = handle->page_buffer2 + (handle->db_head & page_mask);
264
265        if(page_addr == (handle->db_tail & ~sector_mask)){
266                /* head is in the same sector as tail No need to compact */
267                dberr = BFDB_ALREADY_COMPACT;
268                goto ExitFunc;
269        }
270
271        moved_size = erased_size = 0;
272        do {
273                /* fill page buffer */
274                dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, handle->pb_size);
275                if(0 != dberr){
276                        dberr = BFDB_STORE_ERROR;
277                        goto ExitFunc;
278                }
279                tu_id = BFDB_TUPLE_ERASED;
280                while(BFDB_TUPLE_BLANK != tu_id){
281                        tu_id = bfdb_tuple_get_id(pb_walker);
282                        tu_size = bfdb_tuple_get_size(pb_walker) + BFDB_TUPLE_HEAD_SIZE;
283                        switch(tu_id){
284                        case BFDB_TUPLE_ERASED:
285                        case BFDB_TUPLE_LOG:
286                                /* skip this tuple */
287                                erased_size += tu_size;
288                                break;
289                        case BFDB_TUPLE_BLANK:
290                                /* break out of the loop */
291                                continue;
292                        default:
293                                /* check for sector boundary crossing */
294                                o_size = (handle->db_tail & sector_mask) + tu_size + BFDB_LOG_SIZE;
295                                if(0 < (o_size & (~sector_mask))){
296                                        BDBG_ASSERT((BFDB_DATA_MAX+BFDB_TUPLE_HEAD_SIZE) <= o_size);
297                                        dberr = bfdb_log_pad_sector(handle, &o_size);
298                                        if(0 != dberr){
299                                                goto ExitFunc;
300                                        }
301                                }
302                                /* starting new sector */
303                                if(0 == (handle->db_tail & sector_mask)){
304                                        dberr = bfdb_log_open_sector(handle);
305                                        if(0 != dberr){
306                                                goto ExitFunc;
307                                        }
308                                }
309                                /* copy this tuple to the end of the log.*/
310                                if((pb_walker + tu_size) <= (handle->page_buffer2 + handle->pb_size)) {
311                                        dberr = bfdb_log_add(handle, pb_walker, tu_size);
312                                        if(BFDB_OK != dberr){
313                                                goto ExitFunc;
314                                        }
315                                        handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, (pb_walker + BFDB_TUPLE_HEAD_SIZE), (tu_size - BFDB_TUPLE_HEAD_SIZE));
316                                }else{
317                                        /* entire tuple is not in memory, we need to write out
318                                           part in memory and then page in and write out
319                                           remaining part */
320                                        o_size = (handle->page_buffer2 + handle->pb_size) - pb_walker;
321                                        /* page in next page if needed */
322                                        if(o_size < BFDB_TUPLE_HEAD_SIZE){
323                                                dberr = bfds_read(handle->store, (page_addr+handle->pb_size), (handle->page_buffer2 + handle->pb_size), BFDB_PAGE_OVERLAP);
324                                                if(0 != dberr){
325                                                        dberr = BFDB_STORE_ERROR;
326                                                        goto ExitFunc;
327                                                }
328                                                o_size = BFDB_TUPLE_HEAD_SIZE;
329                                        }
330                                        dberr = bfdb_log_add(handle, pb_walker, o_size);
331                                        if(BFDB_OK != dberr){
332                                                goto ExitFunc;
333                                        }
334                                        /* tuple head is always in the first section so skip it for
335                                           checksum */
336                                        handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, (pb_walker + BFDB_TUPLE_HEAD_SIZE), (o_size - BFDB_TUPLE_HEAD_SIZE));
337                                        pb_walker += o_size - handle->pb_size;
338                                        o_size = tu_size - o_size;
339                                        /* page in the next page */
340                                        page_addr += handle->pb_size;
341                                        /* fill page buffer */
342                                        dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, handle->pb_size);
343                                        if(0 != dberr){
344                                                dberr = BFDB_STORE_ERROR;
345                                                goto ExitFunc;
346                                        }
347                                        dberr = bfdb_log_add(handle, pb_walker, o_size);
348                                        if(BFDB_OK != dberr){
349                                                goto ExitFunc;
350                                        }
351                                        /* checksum remaining portion */
352                                        handle->sector_sum32 = bfdb_mod_sum(handle->sector_sum32, pb_walker, o_size);
353                                        /* adjust walker so it will be pointed correctly later */
354                                        pb_walker = pb_walker + o_size - tu_size;
355                                }
356                                moved_size += tu_size;
357                                break;
358                        }
359
360                        pb_walker += tu_size;
361                        if(pb_walker >= (handle->page_buffer2 + handle->pb_size)){
362                                /* read in next page buffer */
363                                break;
364                        }
365                        /* make sure we are away from the end of page_buffer, if not
366                           read a little more data so tuple head is in memory */
367                        if((pb_walker - handle->page_buffer2) > (handle->pb_size - 3)){
368                                dberr = bfds_read(handle->store, (page_addr+handle->pb_size), (handle->page_buffer2 + handle->pb_size), BFDB_PAGE_OVERLAP);
369                                if(0 != dberr){
370                                        dberr = BFDB_STORE_ERROR;
371                                        goto ExitFunc;
372                                }
373                        }
374                }
375                /* prepare to refill next page */
376                pb_walker = pb_walker - handle->pb_size;
377                page_addr += handle->pb_size;
378
379        }while(0 != (page_addr & sector_mask));
380
381        if(page_addr == handle->fl_end){ 
382                page_addr = handle->fl_start; /* wrap */
383        }
384
385        BDBG_ERR(("mov %u era %u pa %08x", moved_size, erased_size, page_addr));
386
387        /* write log start flag and erase previous sector */
388        dberr = bfds_read(handle->store, page_addr, handle->page_buffer2, BFDB_LOG_SIZE);
389        if(0 != dberr){
390                dberr = BFDB_STORE_ERROR;
391                goto ExitFunc;
392        }
393        /* make sure this is a log or blank tuple */
394        tu_id = bfdb_tuple_get_id(handle->page_buffer2);
395        if((BFDB_TUPLE_LOG == tu_id) || (BFDB_TUPLE_BLANK == tu_id)){
396                if(BFDB_TUPLE_BLANK == tu_id){
397                        /* the next sector is blank, start new log */
398                        dberr = bfdb_log_open_sector(handle);
399                        if(0 != dberr){
400                                dberr = BFDB_STORE_ERROR;
401                                goto ExitFunc;
402                        }
403                        handle->page_buffer2[2] = 0xff;
404                }
405                handle->page_buffer2[2] &= ~(BFDB_LF_LOG_START);
406                dberr = bfds_page_program(handle->store, (page_addr+BFDB_TUPLE_HEAD_SIZE), &handle->page_buffer2[2], 1);
407                if(0 != dberr){
408                        dberr = BFDB_STORE_ERROR;
409                        goto ExitFunc;
410                }
411                dberr = bfds_sector_erase(handle->store, handle->db_head);
412                if(0 != dberr){
413                        dberr = BFDB_STORE_ERROR;
414                        goto ExitFunc;
415                }
416                handle->db_head = page_addr;
417        }else{
418                BKNI_Fail();
419                dberr = BFDB_LOG_ERROR;
420        }
421        if(BFDB_DATA_MAX > erased_size){
422                dberr = BFDB_ALREADY_COMPACT;
423        }
424ExitFunc:
425        return dberr;
426}
427/**
428   Iterate over all database sectors erasing each one. Then reload database.
429 */
430bfdb_err bfdb_erase(bfdb_handle handle)
431{
432        uint32_t sector_addr;
433        bfdb_err dberr;
434
435        sector_addr = handle->fl_start;
436        for(sector_addr = handle->fl_start; sector_addr < handle->fl_end; sector_addr += handle->sector_size){
437                dberr = bfds_sector_erase(handle->store, sector_addr);
438                if(0 != dberr){
439                        goto ExitFunc;
440                }
441        }
442        dberr = bfdb_db_load(handle);
443ExitFunc:
444        return dberr;
445}
446
447/**
448   Find log entry point and validate db structures.
449   Log entry must be at sector boundary so we check start of every sector for
450   start database marker. Every sector contains 0xff that means flash is empty.
451 */
452bfdb_err bfdb_db_load(bfdb_handle handle)
453{
454        bfdb_err dberr;
455        unsigned read_offset;
456
457        read_offset = handle->fl_start;
458        do{
459                dberr = bfds_read(handle->store, read_offset, handle->page_buffer, BFDB_LOG_SIZE);
460                if(0 != dberr){
461                        dberr = BFDB_STORE_ERROR;
462                        goto ExitFunc;
463                }
464                if(BFDB_TUPLE_LOG == handle->page_buffer[0]){
465                        break;
466                }
467                read_offset += handle->sector_size;
468        }while(read_offset < handle->fl_end);
469        if(read_offset < handle->fl_end){
470                /* we found log data, now we need to find head and tail of the log */
471                dberr = bfdb_db_load_log(handle, read_offset);
472        }else{
473                /* we did not find log entry anywhere so that means flash is blank */
474                /* read first page and create log tuple in it */
475                read_offset = handle->db_head = handle->db_tail = handle->fl_start;
476
477                bfds_read(handle->store, read_offset, handle->page_buffer, handle->page_size);
478
479                bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, sizeof(struct bfdb_log));
480                handle->page_buffer[2] = ~(BFDB_LF_LOG_START);
481                dberr = bfdb_log_add(handle, handle->page_buffer, sizeof(struct bfdb_log) + BFDB_TUPLE_HEAD_SIZE);
482        }
483ExitFunc:
484        return dberr;
485}
486
487bfdb_err bfdb_db_load_log(bfdb_handle handle, uint32_t offset)
488{
489        bfdb_err dberr;
490        uint8_t * pb_walker;
491        size_t tu_size;
492        uint8_t tu_id;
493        uint32_t checksum;
494        uint8_t * tu_data;
495        uint8_t *pb_end;
496        enum bfdb_rec_state_t rs;
497        uint32_t need_data;
498        uint32_t rcount;
499        /* first we need to find head. This is done by looking at log tuples
500           and checking for a head flag. Since buffer is prescanned we only
501           need to go from the offset to the end of the buffer */
502        do {
503                dberr = bfds_read(handle->store, offset, handle->page_buffer, BFDB_LOG_SIZE);
504                if(0 != dberr){
505                        dberr = BFDB_STORE_ERROR;
506                        goto ExitFunc;
507                }
508                if(BFDB_TUPLE_LOG == handle->page_buffer[0]){
509                        /* found log entry in the sector, check flags for log start */
510                        if(0 == (handle->page_buffer[2] & BFDB_LF_LOG_START)){
511                                break;
512                        }
513                }
514                offset += handle->sector_size;
515        } while(offset < handle->fl_end);
516
517        if(offset == handle->fl_end){
518                /* Not found log entry */
519                dberr = BFDB_LOG_ERROR;
520                goto ExitFunc;
521        }
522        /* Found beginning of the log. Walk tuples to find the end */
523        handle->db_head = offset;
524        pb_walker = handle->page_buffer;
525        pb_end = handle->page_buffer + handle->pb_size;
526        checksum = 0;
527        tu_data = NULL;
528        tu_size = 0;
529        tu_id = 0;
530        rcount = 0;
531        rs = brs_start;
532        need_data = 0;
533        /* do first buffer fill */
534        dberr = bfds_read(handle->store, offset, handle->page_buffer, handle->pb_size);
535        if(0 != dberr){
536                dberr = BFDB_STORE_ERROR;
537                goto ExitFunc;
538        }
539        while(1){
540                if(1 == need_data){
541                        offset += handle->pb_size;
542                        if(offset == handle->fl_end){
543                                /* wrap */
544                                offset = handle->fl_start;
545                        }
546                        pb_walker = pb_walker - handle->pb_size;
547                        BDBG_ASSERT(offset < handle->fl_end);
548                        dberr = bfds_read(handle->store, offset, handle->page_buffer, handle->pb_size);
549                        if(0 != dberr){
550                                dberr = BFDB_STORE_ERROR;
551                                goto ExitFunc;
552                        }
553                        need_data = 0;
554                }
555                switch(rs){
556                case brs_start:
557                        if(pb_walker < pb_end){
558                                tu_id = bfdb_tuple_get_id(pb_walker);
559                                rs = brs_id;
560                        }else{
561                                need_data = 1;
562                                continue;
563                        }
564                case brs_id:
565                        if((pb_walker+1) < pb_end){
566                                tu_size = bfdb_tuple_get_size(pb_walker);
567                                rs = brs_size;
568                        }else{
569                                need_data = 1;
570                                continue;
571                        }
572                case brs_size:
573                        if((pb_walker + BFDB_TUPLE_HEAD_SIZE) < pb_end){
574                                tu_data = pb_walker + BFDB_TUPLE_HEAD_SIZE;
575                                rs = brs_data;
576                        }else{
577                                need_data = 1;
578                                continue;
579                        }
580                default:
581                        break;
582                }
583                if(BFDB_TUPLE_LOG == tu_id){
584                        /* log entries never cross page boundaries so they are safe */
585                        uint32_t log_sum;
586                        log_sum = ((struct bfdb_log*)tu_data)->checksum;
587                        if((log_sum != checksum) && (log_sum != 0xffffffff)){
588                                dberr = BFDB_LOG_ERROR;
589                                goto ExitFunc;
590                        }
591                        checksum = 0;
592                }else if(BFDB_TUPLE_BLANK == tu_id){
593                        /* found end of log */
594                        handle->db_tail = offset + (pb_walker - handle->page_buffer);
595                        handle->sector_sum32 = checksum;
596                        dberr = BFDB_OK;
597                        goto ExitFunc;
598                }else{
599                        /* regular tuple, can be all in this page, part in this page or
600                           all in the next page */
601                        switch(rs){
602                        case brs_data:
603                                if(((tu_data + tu_size) < pb_end)){
604                                        checksum = bfdb_mod_sum(checksum, tu_data, tu_size);
605                                        rcount++;
606                                }else{
607                                        checksum = bfdb_mod_sum(checksum, tu_data, (pb_end - tu_data));
608                                        pb_walker += (pb_end - tu_data);
609                                        tu_size = tu_size - (pb_end - tu_data);
610                                        tu_data = handle->page_buffer;
611                                        need_data = 1;
612                                        rs = brs_data2;
613                                        continue;
614                                }
615                                break;
616                        case brs_data2:
617                                /* second part of the tuple */
618                                checksum = bfdb_mod_sum(checksum, tu_data, tu_size);
619                                rcount++;
620                                break;
621                        default:
622                                BKNI_Fail();
623                        }
624                }
625                pb_walker += tu_size + BFDB_TUPLE_HEAD_SIZE;
626                rs = brs_start;
627        }
628
629ExitFunc:
630        return dberr;
631}
632
633/* Tuple operations */
634
635/* Create tuple head in given buffer */
636void bfdb_tuple_put_head( void * buf, uint8_t id, uint8_t size )
637{
638        ((uint8_t *)buf)[0] = id;
639        ((uint8_t *)buf)[1] = size;
640}
641/* get tuple size */
642uint32_t bfdb_tuple_get_size(void * tuple)
643{
644        return (uint32_t)(((uint8_t *)tuple)[1]);
645}
646/* get tuple id */
647uint32_t bfdb_tuple_get_id(void * tuple)
648{
649        return (uint32_t)(((uint8_t *)tuple)[0]);
650}
651
652/*
653  Iterate through database looking for a tuple with given "id" startting
654  at position "start".
655  Function will return BFDB_OK if such tuple found or error code if no
656  tuple with given id was found. The actual tuple position will be placed
657  in to handle->cursor;
658 */
659bfdb_err bfdb_log_walk(bfdb_handle handle, uint32_t start, uint8_t id)
660{
661        bfdb_err dberr;
662        uint8_t * pb_walker;
663        size_t tu_size;
664        uint8_t tu_id;
665        uint32_t page_mask;
666        uint32_t page_addr;
667        uint8_t * pb_end;
668        enum bfdb_rec_state_t rs;
669        uint32_t need_data;
670        uint32_t wrap_check;
671
672        page_mask = handle->pb_size - 1; /* pb_size must be pow of 2 */
673        page_addr = (start & ~page_mask) - handle->pb_size;
674        pb_end = handle->page_buffer + handle->pb_size;
675        pb_walker = pb_end + (start & page_mask);
676        need_data = 1;
677        rs = brs_start;
678        wrap_check = 0;
679        tu_size = 0;
680        tu_id = 0;
681
682        while(start != handle->db_tail){
683                if(1 == need_data){
684                        page_addr += handle->pb_size;
685                        if(page_addr == handle->fl_end){
686                                /* wrap */
687                                start = start - page_addr + handle->fl_start;
688                                if(start == handle->db_tail){
689                                        continue;       /* terminate loop */
690                                }
691                                page_addr = handle->fl_start;
692                                BDBG_ASSERT(start >= handle->fl_start);
693                                BDBG_ASSERT(start < handle->fl_end);
694                                wrap_check++;
695                                BDBG_ASSERT(wrap_check < 2);
696                        }
697                        pb_walker = pb_walker - handle->pb_size;
698
699                        BDBG_ASSERT(page_addr < handle->fl_end);
700
701                dberr = bfds_read(handle->store, page_addr, handle->page_buffer, handle->pb_size);
702                if(0 != dberr){
703                        dberr = BFDB_STORE_ERROR;
704                        goto ExitFunc;
705                }
706                        need_data = 0;
707                }
708                switch(rs){
709                case brs_start:
710                        if(pb_walker < pb_end){
711                                tu_id = bfdb_tuple_get_id(pb_walker);
712                                rs = brs_id;
713                        }else{
714                                need_data = 1;
715                                continue;
716                        }
717                case brs_id:
718                        if((pb_walker+1) < pb_end){
719                        tu_size = bfdb_tuple_get_size(pb_walker);
720                                rs = brs_size;
721                        }else{
722                                need_data = 1;
723                                continue;
724                        }
725                case brs_size:
726                default:
727                                break;
728                        }
729                BDBG_ASSERT(id != BFDB_TUPLE_BLANK);
730                /* we got id and size, now compare and advance */
731                if(id == tu_id){
732                        /* found desired tuple */
733                        handle->cursor = page_addr + (pb_walker - handle->page_buffer);
734                        dberr = BFDB_OK;
735                        goto ExitFunc;
736                }else{
737                        pb_walker += tu_size + BFDB_TUPLE_HEAD_SIZE;
738                        start += tu_size + BFDB_TUPLE_HEAD_SIZE;
739                        rs = brs_start;
740                }
741        }
742        dberr = BFDB_RECORD_NOT_FOUND;
743ExitFunc:
744        return dberr;
745}
746
747/**
748   Add data at the end of the log.
749   bfdb_log_add will add data to the end of the log. It operates
750   within sector boundaries but across page boundaries. Calling code must
751   make sure that tuple will not cross sector boundaries.
752   Call will advance database tail by the amount of added data.
753 */
754bfdb_err bfdb_log_add(bfdb_handle handle, uint8_t * data, size_t dsize)
755{
756        bfdb_err dberr;
757        uint32_t o_size1;
758        uint32_t o_size2;
759        uint32_t page_mask;
760
761        /* locate pages to load in the buffer */
762        page_mask = handle->page_size - 1;      /* page size must be power of 2 */
763
764        /* calculate transfer sizes */
765        o_size1 = (handle->db_tail & page_mask) + dsize;
766        if(0 < (o_size1 & (~page_mask))){
767                /* we cross page boundary */
768                o_size1 = handle->page_size - (handle->db_tail & page_mask);
769                o_size2 = dsize - o_size1;
770        }else{
771                o_size1 = dsize;
772                o_size2 = 0;
773        }
774
775        do {
776                uint32_t sector_mask;
777                sector_mask = handle->sector_size - 1;
778                if(0 == (handle->db_tail & sector_mask)){
779                        if(BFDB_TUPLE_LOG != data[0])
780                                BKNI_Fail();
781                }
782               
783        } while(0);
784
785        dberr = bfds_page_program(handle->store, handle->db_tail, data, o_size1);
786        if(0 != dberr){
787                dberr = BFDB_STORE_ERROR;
788                goto ExitFunc;
789        }
790        handle->db_tail += o_size1;
791        if(0 != o_size2){
792                BDBG_ASSERT(0 == (handle->db_tail & page_mask));
793                dberr = bfds_page_program(handle->store, handle->db_tail, data+o_size1, o_size2);
794                if(0 != dberr){
795                        dberr = BFDB_STORE_ERROR;
796                        goto ExitFunc;
797                }
798                handle->db_tail += o_size2;
799        }
800        dberr = BFDB_OK;
801ExitFunc:
802        return dberr;
803}
804
805/**
806   Pad log with log tuple to the sector boundary.
807 */
808bfdb_err bfdb_log_pad_sector(bfdb_handle handle, size_t * padded_size)
809{
810        uint32_t o_size;
811        uint32_t o_size1;
812        uint32_t sector_mask;
813        bfdb_err dberr;
814        struct bfdb_log * plog;
815
816        sector_mask = handle->sector_size - 1; /* sector size must be power of 2 */
817        o_size = handle->sector_size - (handle->db_tail & sector_mask);
818        BDBG_ASSERT(o_size >= BFDB_LOG_SIZE);
819        o_size1 = 0; 
820        if(o_size >= (BFDB_TUPLE_HEAD_SIZE + BFDB_DATA_MAX)){
821                /* we need to pad with two tuples */
822                o_size1 = o_size / 2;
823                BKNI_Memset(handle->page_buffer, 0xff, o_size1);
824                bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, (o_size1 - BFDB_TUPLE_HEAD_SIZE));
825                dberr = bfdb_log_add(handle, handle->page_buffer, o_size1);
826                if(0 != dberr){
827                        goto ExitFunc;
828                }
829        }
830        o_size = o_size - o_size1;
831        BKNI_Memset(handle->page_buffer, 0xff, o_size);
832        bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, (o_size - BFDB_TUPLE_HEAD_SIZE));
833        plog = (struct bfdb_log*)&handle->page_buffer[2];
834        plog->checksum = handle->sector_sum32;
835
836        dberr = bfdb_log_add(handle, handle->page_buffer, o_size);
837        if(0 != dberr){
838                goto ExitFunc;
839        }
840        if(handle->fl_end <= handle->db_tail){
841                BDBG_ASSERT(handle->fl_end == handle->db_tail);
842                handle->db_tail = handle->fl_start;
843        }
844        BDBG_ASSERT(0 == (handle->db_tail & sector_mask));
845        *padded_size = o_size + o_size1;
846ExitFunc:
847        return dberr;
848}
849
850/**
851   Create log entry in the new sector. Wrap in the log if required.
852 */
853bfdb_err bfdb_log_open_sector(bfdb_handle handle)
854{
855        bfdb_err dberr;
856
857        /* check if we must wrap */
858        if(handle->fl_end <= handle->db_tail){
859                BDBG_ASSERT(handle->fl_end == handle->db_tail);
860                handle->db_tail = handle->fl_start;
861        }
862        BKNI_Memset(handle->page_buffer, 0xff, 8);
863        bfdb_tuple_put_head(handle->page_buffer, BFDB_TUPLE_LOG, sizeof(struct bfdb_log));
864        dberr = bfdb_log_add(handle, handle->page_buffer, (sizeof(struct bfdb_log) + BFDB_TUPLE_HEAD_SIZE));
865        handle->sector_sum32 = 0;
866
867        return dberr;
868}
869
870uint32_t bfdb_mod_sum(uint32_t sum, uint8_t * data, size_t dsize)
871{
872        size_t i;
873        if(dsize > 0xff){
874                BKNI_Fail();
875        }
876        for(i = 0 ; i < dsize; i++){
877                sum += data[i];
878        }
879        return sum;
880}
881
882/* Please do not remove! */
883/* Local Variables: */
884/* mode: C */
885/* indent-tabs-mode: t */
886/* End: */
Note: See TracBrowser for help on using the repository browser.