source: svn/trunk/newcon3bcm2_21bu/BSEAV/lib/bfile/bfile_cache.c @ 9

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

first commit

  • Property svn:executable set to *
File size: 17.4 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2007-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: bfile_cache.c $
11 * $brcm_Revision: 14 $
12 * $brcm_Date: 6/25/10 12:00p $
13 *
14 * Module Description:
15 *
16 * Linear file cache
17 *
18 * Revision History:
19 *
20 * $brcm_Log: /BSEAV/lib/bfile/bfile_cache.c $
21 *
22 * 14   6/25/10 12:00p vsilyaev
23 * SW3548-2995: Separate requested reserve size and minimal size for
24 * succesive parsing
25 *
26 * 13   6/3/10 1:58p vsilyaev
27 * SW7405-4414: Improved debug messages
28 *
29 * 12   4/8/10 6:53p vsilyaev
30 * SW7405-3773: Use 64-bit integer for segment size
31 *
32 * 11   2/11/10 5:28p vsilyaev
33 * SW7408-75: Fixed use of unitialized variable
34 *
35 * 10   1/13/10 5:06p vsilyaev
36 * SW3556-913: Remeber file I/O related errors and propagate them
37 *
38 * 9   1/12/10 7:57p vsilyaev
39 * SW3556-913: Separate data and index reads, allow incomplete data reads
40 *
41 * 8   1/11/10 7:35p vsilyaev
42 * SW3556-913: Added function to differentiate between end of cached data
43 * and file error
44 *
45 * 7   11/23/09 4:11p vsilyaev
46 * SW7405-3368: Added parsing of MKV attachments
47 *
48 * 6   9/4/08 12:56p vsilyaev
49 * PR 46412: Fixed debug output
50 *
51 * 5   8/18/08 12:41p gmohile
52 * PR 42817 : Add support for AVI2.0
53 * 
54 * 4   7/9/07 4:08p vsilyaev
55 * PR 32773: Improved debug output
56 *
57 * 3   5/10/07 7:24p vsilyaev
58 * PR 28631: Improved debug output and optimized bfile_cache_next
59 *
60 * 2   5/10/07 5:08p vsilyaev
61 * PR 28631: Allow seek to just right past last valid byte
62 *
63 * 1   4/29/07 12:54a vsilyaev
64 * PR 28631: File cache utilities
65 *
66 *
67 *******************************************************************************/
68#include "bstd.h"
69#include "bkni.h"
70#include "bfile_cache.h"
71
72BDBG_MODULE(bfile_cache);
73
74#define BDBG_MSG_TRACE(x) /* BDBG_MSG(x) */
75
76
77void 
78bfile_segment_clear(bfile_segment *segment)
79{
80        segment->start = -1;
81        segment->len = 0;
82        return;
83}
84
85void
86bfile_segment_set(bfile_segment *segment, off_t start, uint64_t len)
87{
88        segment->start = start;
89        segment->len = len;
90        return;
91}
92
93bool
94bfile_segment_test(const bfile_segment *segment)
95{
96        return segment->len>0 && segment->start>0;
97}
98
99BDBG_OBJECT_ID(bfile_cache_t);
100
101struct bfile_cache {
102        BDBG_OBJECT(bfile_cache_t)
103        size_t cur_pos; /* current position in the buffer */
104        size_t atom_size;
105        size_t cur_size; /* number of bytes loaded into the buffer */
106        size_t cur_off; /* current offset from start of segment */
107        bfile_segment segment;
108        size_t buf_size;
109    bool file_error;
110        bfile_io_read_t  fd;
111        uint8_t buffer[1]; /* variable size array for the cache */
112};
113
114bfile_cache_t
115bfile_cache_create(bfile_io_read_t fd, const bfile_segment *segment, size_t buf_size, size_t atom_size)
116{
117        bfile_cache_t cache;
118
119        BDBG_ASSERT(fd);
120        BDBG_ASSERT(segment);
121        if(atom_size>buf_size) {
122                BDBG_ERR(("bfile_cache_create: buf_size%u shall be larget then atom_size:%u", buf_size, atom_size));
123                return NULL;
124        }
125        if(!bfile_segment_test(segment)) {
126                BDBG_ERR(("bfile_cache_create: segment doesn't point to valid data"));
127                return NULL;
128        }
129        cache = BKNI_Malloc(sizeof(*cache)+buf_size);
130        if(!cache) {
131                BDBG_ERR(("bfile_cache_create: can't allocate %u bytes", sizeof(*cache)+buf_size));
132                return NULL;
133        }
134        BDBG_OBJECT_INIT(cache, bfile_cache_t);
135        cache->segment = *segment;
136        cache->fd = fd;
137        cache->atom_size = atom_size;
138        cache->buf_size = buf_size;
139        cache->cur_size = 0;
140        cache->cur_pos = 0;
141        cache->cur_off = 0;
142        cache->cur_size = 0;
143    cache->file_error = false;
144        BDBG_MSG(("bfile_cache_create: %#lx buf_size:%u atom_size:%u size:%u start:%lld", (unsigned long)cache, (unsigned)cache->buf_size, (unsigned)cache->atom_size, (unsigned)cache->segment.len, cache->segment.start));
145        return cache;
146}
147
148void
149bfile_cache_destroy( bfile_cache_t  cache)
150{
151        BDBG_OBJECT_ASSERT(cache, bfile_cache_t);
152        BDBG_OBJECT_DESTROY(cache, bfile_cache_t);
153        BKNI_Free(cache);
154        return;
155}
156
157void
158bfile_cache_clear( bfile_cache_t  cache)
159{
160        BDBG_OBJECT_ASSERT(cache, bfile_cache_t);
161
162        cache->cur_size = 0;
163        cache->cur_pos = 0;
164        cache->cur_off = 0;
165        cache->cur_size = 0;
166    cache->file_error = false;
167        return;
168}
169
170void 
171bfile_segment_reset( bfile_cache_t  cache, bfile_segment *segment)
172{
173        BDBG_OBJECT_ASSERT(cache, bfile_cache_t);
174       
175        cache->segment = *segment;
176        return;
177}
178       
179
180int
181bfile_cache_seek(bfile_cache_t cache, size_t off)
182{
183        BDBG_OBJECT_ASSERT(cache, bfile_cache_t);
184        if(off>cache->segment.len) {
185                BDBG_WRN(("seek out of bounds %lld (%u)", off, cache->segment.len));
186                return -1;
187        }
188        if(off>= cache->cur_off && (off + cache->atom_size) < (cache->cur_off + cache->cur_size)) {
189                /* location is already in cache */
190                cache->cur_pos = off - cache->cur_off;
191        } else {
192                cache->cur_size = 0; /* forces reload on next read */
193                if(off > cache->cur_off) { /* seek forward, preload from new offset */
194                        cache->cur_off = off;
195                        cache->cur_pos = 0;
196                } else { /* seek back, preload from tail */
197                        if(off >= (cache->buf_size-cache->atom_size)) {
198                                cache->cur_off = off - (cache->buf_size-cache->atom_size);
199                                cache->cur_pos = (cache->buf_size-cache->atom_size);
200                        } else {
201                                cache->cur_off = 0;
202                                cache->cur_pos = off;
203                        }
204                }
205        }
206    cache->file_error = false;
207        BDBG_ASSERT(cache->cur_off + cache->cur_pos == off); /* verify our calculcations */
208        return 0;
209}
210
211const uint8_t *
212bfile_cache_next(bfile_cache_t cache)
213{
214        size_t new_off;
215        size_t to_read;
216        ssize_t read_result;
217        off_t seek_result;
218        off_t seek_dest;
219        size_t atom_size;
220
221        BDBG_OBJECT_ASSERT(cache, bfile_cache_t);
222        atom_size = cache->atom_size;
223        for(;;) {
224                size_t cur_size = cache->cur_size;
225
226                new_off = cache->cur_pos + atom_size;
227                if(new_off <= cur_size) {
228                        const uint8_t *buf=&cache->buffer[cache->cur_pos];
229                        cache->cur_pos = new_off;
230                        return buf;
231                }
232                new_off = cache->cur_off;
233                if(cur_size > 0) { /* normal read */
234                        new_off += cache->cur_pos; /* advance to new offset */
235                } 
236                to_read = cache->buf_size;
237                if(new_off + to_read >= cache->segment.len) {
238                        if(new_off >= cache->segment.len) {
239                                BDBG_MSG(("bfile_cache_next:%#lx EOF reached %lu(%lu)", (unsigned long)cache, (unsigned long)new_off, (unsigned long)cache->segment.len));
240                                return NULL;
241                        }
242                        to_read = cache->segment.len - new_off;
243                }
244                seek_dest = cache->segment.start + new_off;
245                BDBG_MSG(("bfile_cache_next:%#lx read %u bytes at %lld", (unsigned long)cache, (unsigned)to_read, seek_dest));
246                seek_result = cache->fd->seek(cache->fd, seek_dest, SEEK_SET);
247                if(seek_result!=seek_dest) {
248            cache->file_error = true;
249                        BDBG_WRN(("bfile_cache_next:%#lx seek error %lld(%lld)", (unsigned long)cache, seek_result, seek_dest));
250                        return NULL;
251                }
252                read_result =  cache->fd->read(cache->fd, cache->buffer, to_read);
253                if(read_result<=0 || read_result<(ssize_t)atom_size) {
254            cache->file_error = true;
255                        BDBG_WRN(("bfile_cache_next:%#lx read error %ld (%lld:%lld)", (unsigned long)cache, (long)read_result, (long)seek_dest, (long)(cache->segment.start+cache->segment.len)));
256                        return NULL;
257                }
258                if(cur_size > 0) {
259                        cache->cur_pos = 0; /* clear position */
260                } else { /* fill read */
261                        if(read_result < (ssize_t)(cache->cur_pos+atom_size)) {
262                if((size_t)read_result<to_read) {
263                                    BDBG_WRN(("bfile_cache_next: %#lx haven't read enough data %ld:%u:%u(%u:%u)", (unsigned long)cache, (long)read_result, (unsigned)to_read, (unsigned)cache->cur_pos+atom_size, (unsigned)cache->cur_pos, (unsigned)atom_size));
264                } else {
265                                    BDBG_WRN(("bfile_cache_next: %#lx not enough data %ld:%u:%u(%u:%u)", (unsigned long)cache, (long)read_result, (unsigned)to_read, (unsigned)cache->cur_pos+atom_size, (unsigned)cache->cur_pos, (unsigned)atom_size));
266                }
267                                return NULL;
268                        }
269                } 
270                cache->cur_size = read_result;
271                cache->cur_off = new_off;
272        cache->file_error = false;
273                BDBG_ASSERT(cache->cur_pos + atom_size <=  cache->cur_size); /* verify that we did our math right */
274        }
275}
276
277int
278bfile_cached_segment_init(bfile_cached_segment *segment, bfile_buffer_t buffer, batom_factory_t factory, size_t min_read_size)
279{
280        BDBG_ASSERT(segment);
281        BDBG_ASSERT(buffer);
282        BDBG_ASSERT(factory);
283        BDBG_ASSERT(min_read_size>0);
284        segment->accum = batom_accum_create(factory);
285        if(!segment->accum) {
286                return -1;
287        }
288        bfile_segment_clear(&segment->segment);
289        batom_cursor_from_accum(&segment->cursor, segment->accum);
290        segment->accum_offset = 0;
291        segment->buffer = buffer;
292        segment->min_read_size = min_read_size;
293        segment->async.cntx = NULL;
294        segment->async.read_complete = NULL;
295        segment->async.accum_size = 0;
296        return 0;
297}
298
299bool
300bfile_cache_is_file_error(bfile_cache_t cache)
301{
302    return cache->file_error;
303}
304
305void
306bfile_cached_segment_shutdown(bfile_cached_segment *segment)
307{
308        batom_accum_destroy(segment->accum);
309        return;
310}
311
312
313void
314bfile_cached_segment_seek(bfile_cached_segment *segment, uint64_t offset)
315{
316        batom_accum_clear(segment->accum);
317        batom_cursor_from_accum(&segment->cursor, segment->accum);
318        segment->accum_offset = offset;
319        if(offset>segment->segment.len) {
320                BDBG_WRN(("bfile_cached_segment_seek: %#lx outside of bounds %u:%u", (unsigned long)segment, (unsigned)offset, (unsigned)segment->segment.len));
321        }
322        return;
323}
324
325uint64_t
326bfile_cached_segment_tell(bfile_cached_segment *segment)
327{
328        return segment->accum_offset + batom_cursor_pos(&segment->cursor);
329}
330
331void
332bfile_cached_segment_set(bfile_cached_segment *segment, off_t start, uint64_t len)
333{
334    BDBG_ASSERT(start>=0);
335        bfile_cached_segment_seek(segment, 0);
336        bfile_segment_set(&segment->segment, start, len);
337        return;
338}
339
340
341static bfile_segment_async_result
342b_file_cached_segment_convert_result(bfile_buffer_result buffer_result)
343{
344    switch(buffer_result) {
345    case bfile_buffer_result_ok:
346        return bfile_segment_async_result_success;
347    case bfile_buffer_result_async:
348        return bfile_segment_async_result_async;
349    case bfile_buffer_result_no_data:
350        return bfile_segment_async_result_no_data;
351    case bfile_buffer_result_eof:
352        return bfile_segment_async_result_eof;
353    default:
354        return bfile_segment_async_result_error;
355    }
356}
357
358static void 
359b_file_cached_segment_async_read_complete(void *cntx, batom_t atom, bfile_buffer_result result)
360{
361        bfile_cached_segment *segment = cntx;
362
363    BSTD_UNUSED(result);
364    segment->last_read_result = result;
365        if(atom) {
366                batom_accum_add_atom(segment->accum, atom);
367            BDBG_MSG_TRACE(("%s:%#lx read block data buffer:%#lx at %u size:%u total:%u", "b_file_cached_segment_async_read_complete", (unsigned long)segment, (unsigned long)segment->buffer, (unsigned)(segment->segment.start + segment->accum_offset+segment->async.accum_size), batom_len(atom), batom_accum_len(segment->accum)));
368                batom_cursor_from_accum(&segment->cursor, segment->accum);
369                batom_release(atom);
370                segment->async.read_complete(segment->async.cntx, b_file_cached_segment_convert_result(result));
371        } else {
372            BDBG_MSG_TRACE(("%s:%#lx read block failed buffer:%#lx at %u size:%u accum:%u", "b_file_cached_segment_async_read_complete", (unsigned long)segment, (unsigned long)segment->buffer, (unsigned)(segment->segment.start + segment->accum_offset+segment->async.accum_size), segment->async.load_size, batom_accum_len(segment->accum)));
373                segment->async.read_complete(segment->async.cntx, b_file_cached_segment_convert_result(result));
374        }
375}
376
377bfile_segment_async_result
378bfile_cached_segment_async_reserve(bfile_cached_segment *segment, size_t reserve_size, void (*read_complete)(void *, bfile_segment_async_result ), void *cntx)
379{
380        size_t accum_size;
381        batom_t atom;
382        size_t load_size;
383        size_t cursor_pos;
384
385        accum_size = batom_accum_len(segment->accum);
386        cursor_pos = batom_cursor_pos(&segment->cursor);
387    segment->last_read_result = bfile_buffer_result_ok;
388        if(accum_size >= reserve_size + cursor_pos) { /* we need min_size of _new_ data, so account here current position of cursor */
389                return bfile_segment_async_result_success;
390        }
391        batom_accum_trim(segment->accum, &segment->cursor); /* recycle old data */
392        segment->accum_offset += cursor_pos;
393        accum_size -= cursor_pos;
394        BDBG_ASSERT(accum_size == batom_accum_len(segment->accum));
395        BDBG_ASSERT(reserve_size > accum_size);
396        load_size = reserve_size - accum_size;
397        if(load_size<segment->min_read_size) { /* read at least B_MKV_PLAYER_CLUSTER_ENTRY */
398                load_size = segment->min_read_size;
399        }
400        if(segment->accum_offset + load_size >  segment->segment.len) { /* don't read outside of segment boundary */
401                if(segment->segment.len <= segment->accum_offset) {
402                        BDBG_MSG_TRACE(("%s:%#lx end of data %u:%u", "bfile_cached_segment_async_reserve", (unsigned long)segment, (unsigned)segment->segment.len, (unsigned)segment->accum_offset));
403                        return bfile_segment_async_result_eof;
404                }
405                load_size = segment->segment.len - segment->accum_offset;
406                BDBG_ASSERT(load_size>0);
407        }
408        BDBG_MSG_TRACE(("%s:%#lx reading block data buffer:%#lx at %u size:%u", "bfile_cached_segment_async_reserve", (unsigned long)segment, (unsigned long)segment->buffer, (unsigned)(segment->segment.start + segment->accum_offset+accum_size), load_size));
409        segment->async.accum_size = accum_size;
410        segment->async.load_size = load_size;
411        segment->async.cntx = cntx;
412        segment->async.read_complete = read_complete;
413        atom = bfile_buffer_async_read(segment->buffer, segment->segment.start + segment->accum_offset + accum_size, load_size, &segment->last_read_result, b_file_cached_segment_async_read_complete, segment);
414        if(segment->last_read_result == bfile_buffer_result_ok && atom) {
415                batom_accum_add_atom(segment->accum, atom);
416            BDBG_MSG_TRACE(("%s:%#lx read block data buffer:%#lx at %u size:%u total:%u", "bfile_cached_segment_async_reserve", (unsigned long)segment, (unsigned long)segment->buffer, (unsigned)(segment->segment.start + segment->accum_offset+accum_size), batom_len(atom), batom_accum_len(segment->accum)));
417                batom_cursor_from_accum(&segment->cursor, segment->accum);
418                batom_release(atom);
419                return bfile_segment_async_result_success;
420        } else {
421        if(atom) {
422            batom_release(atom);
423        }
424        return b_file_cached_segment_convert_result(segment->last_read_result);
425        }
426}
427
428
429bool
430bfile_cached_segment_reserve_custom_buffer_min(bfile_cached_segment *segment, size_t reserve_size, size_t min_size, bfile_buffer_t buffer)
431{
432        size_t accum_size;
433        batom_t atom;
434        size_t load_size;
435        size_t cursor_pos;
436
437    BDBG_ASSERT(reserve_size>=min_size);
438
439        accum_size = batom_accum_len(segment->accum);
440        cursor_pos = batom_cursor_pos(&segment->cursor);
441    segment->last_read_result = bfile_buffer_result_ok;
442        if(accum_size >= reserve_size + cursor_pos) { /* we need min_size of _new_ data, so account here current position of cursor */
443                return true;
444        }
445        batom_accum_trim(segment->accum, &segment->cursor); /* recycle old data */
446    batom_cursor_from_accum(&segment->cursor, segment->accum); /* reseed cursor */
447        segment->accum_offset += cursor_pos;
448        accum_size -= cursor_pos;
449        BDBG_ASSERT(accum_size == batom_accum_len(segment->accum));
450        BDBG_ASSERT(reserve_size > accum_size);
451        load_size = reserve_size - accum_size;
452        if(load_size<segment->min_read_size) { /* read at least min_read_size */
453                load_size = segment->min_read_size;
454        }
455        if(segment->accum_offset + load_size >  segment->segment.len) { /* don't read outside of segment boundary */
456                if(segment->segment.len <= segment->accum_offset) {
457                        BDBG_MSG_TRACE(("%s:%#lx end of data %u:%u", "bfile_cached_segment_reserve_custom_buffer_min", (unsigned long)segment, (unsigned)segment->segment.len, (unsigned)segment->accum_offset));
458                        return false;
459                }
460                load_size = segment->segment.len - segment->accum_offset;
461                BDBG_ASSERT(load_size>0);
462        }
463        BDBG_MSG_TRACE(("%s:%#lx reading block data buffer:%#lx at %u size:%u(%u:%u)", "bfile_cached_segment_reserve_custom_buffer_min", (unsigned long)segment, (unsigned long)buffer, (unsigned)(segment->segment.start + segment->accum_offset+accum_size), load_size, reserve_size, min_size));
464        atom = bfile_buffer_read(buffer, segment->segment.start + segment->accum_offset + accum_size, load_size, &segment->last_read_result);
465        if(atom) {
466                batom_accum_add_atom(segment->accum, atom);
467            BDBG_MSG_TRACE(("%s:%#lx read block data buffer:%#lx at %u size:%u total:%u", "bfile_cached_segment_reserve_custom_buffer_min", (unsigned long)segment, (unsigned long)buffer, (unsigned)(segment->segment.start + segment->accum_offset+accum_size), batom_len(atom), batom_accum_len(segment->accum)));
468                batom_cursor_from_accum(&segment->cursor, segment->accum);
469                batom_release(atom);
470        } else {
471            BDBG_MSG_TRACE(("%s:%#lx read block failed buffer:%#lx at %u size:%u(%u) result:%u accum:%u", "bfile_cached_segment_reserve_custom_buffer_min", (unsigned long)segment, (unsigned long)buffer, (unsigned)(segment->segment.start + segment->accum_offset+accum_size), load_size, min_size, segment->last_read_result, batom_accum_len(segment->accum)));
472        }
473    return batom_accum_len(segment->accum)>=min_size;
474}
475
476bool
477bfile_cached_segment_reserve_custom_buffer(bfile_cached_segment *segment, size_t reserve_size, bfile_buffer_t buffer)
478{
479    return bfile_cached_segment_reserve_custom_buffer_min(segment, reserve_size, reserve_size, buffer);
480}
481
482bool
483bfile_cached_segment_reserve(bfile_cached_segment *segment, size_t reserve_size)
484{
485    return bfile_cached_segment_reserve_custom_buffer_min(segment, reserve_size, reserve_size, segment->buffer);
486}
487
488bool
489bfile_cached_segment_reserve_min(bfile_cached_segment *segment, size_t reserve_size, size_t min_size)
490{
491    return bfile_cached_segment_reserve_custom_buffer_min(segment, reserve_size, min_size, segment->buffer);
492}
493
Note: See TracBrowser for help on using the repository browser.