source: svn/trunk/newcon3bcm2_21bu/nexus/modules/file/src/nexus_file_chunk.c

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

first commit

  • Property svn:executable set to *
File size: 17.0 KB
Line 
1/***************************************************************************
2 *     (c)2003-2010 Broadcom Corporation
3 * 
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. 
13 *   
14 *  Except as expressly set forth in the Authorized License,
15 *   
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *   
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 * 
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_file_chunk.c $
39 * $brcm_Revision: 1 $
40 * $brcm_Date: 4/22/10 6:57p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/file/src/nexus_file_chunk.c $
47 *
48 * 1   4/22/10 6:57p mphillip
49 * SW7405-4251: Merge chunked PVR support from branch to main
50 *
51 * SW7405-3587/3   4/22/10 12:01p mphillip
52 * SW7405-4251: Update chunked PVR after API review, prepare for merge to
53 *  main.
54 *
55 * SW7405-3587/2   4/15/10 10:54a jrubio
56 * SW7405-3587: nexu_file_pvr.h has moved
57 *
58 *
59 *
60 *
61 *
62 ***************************************************************************/
63
64#include "nexus_file_module.h"
65#include "bstd.h"
66#include "bkni.h"
67#include "bkni_multi.h"
68#include "blst_queue.h"
69#include "bcmplayer.h"
70#include "bcmindexer.h"
71#include "bfile_io.h"
72#include "nexus_file_pvr.h"
73#include "nexus_file_types.h"
74#include "nexus_file_posix.h"
75
76BDBG_MODULE(fileio_chunk);
77
78#if 0
79/* just to exercise more corner cases */
80#define B_DEFAULT_CHUNK_SIZE    (73*4095)
81#else
82/* for now just reasonable big number */
83#define B_DEFAULT_CHUNK_SIZE    (256*1024*1024)
84#endif
85#define B_MAX_FILE_LEN  128
86#define B_FIRST_CHUNK   1
87
88
89struct bfile_io_write_chunk {
90    struct bfile_io_write self;
91    NEXUS_FileRecordHandle data; /* current data file */
92    unsigned chunk; /* current chunk */
93    size_t  chunk_budget; /* number of bytes left in the chunk */
94    NEXUS_FileRecordHandle (*open_out)(const char *fname, const char *indexname);
95    NEXUS_ChunkedFileRecordOpenSettings settings;
96    char base_name[B_MAX_FILE_LEN];
97};
98
99void NEXUS_ChunkedFilePlay_GetDefaultOpenSettings(
100    NEXUS_ChunkedFilePlayOpenSettings *pSettings /* [out] */
101    )
102{
103    BKNI_Memset(pSettings, 0, sizeof(NEXUS_ChunkedFilePlayOpenSettings));
104    pSettings->chunkSize = B_DEFAULT_CHUNK_SIZE;
105}
106
107void NEXUS_ChunkedFileRecord_GetDefaultOpenSettings(
108    NEXUS_ChunkedFileRecordOpenSettings *pSettings /* [out] */
109    )
110{
111    BKNI_Memset(pSettings, 0, sizeof(NEXUS_ChunkedFileRecordOpenSettings));
112    pSettings->chunkSize = B_DEFAULT_CHUNK_SIZE;
113}
114
115
116static void
117get_chunk_name(char *buf, const char *name, unsigned chunk)
118{
119    BKNI_Snprintf(buf, B_MAX_FILE_LEN, "%s/chunk.%u", name, chunk);
120}
121
122static ssize_t
123chunk_write(bfile_io_write_t fd, const void *buf_, size_t length)
124{
125    struct bfile_io_write_chunk *file = (struct bfile_io_write_chunk *) fd;
126    ssize_t result;
127    const void *buf = buf_;
128
129
130    for(result=0;length>0;) {
131        size_t to_write = length;
132        ssize_t rc;
133        char name[B_MAX_FILE_LEN];
134
135        if (file->chunk_budget==0) { /* time to open new file */
136            if(file->data) { 
137                NEXUS_FileRecord_Close(file->data);
138            }
139            file->chunk++;
140            get_chunk_name(name, file->base_name, file->chunk);
141            BDBG_MSG(("write opening %s", name));
142            file->data = file->open_out(name, NULL);
143            file->chunk_budget = file->settings.chunkSize;
144        }
145        if (!file->data) { /* if file isn't opened at this point we are dead */
146            if (result==0) {
147                result = -1;
148            }
149            break;
150        }
151
152        if (to_write>file->chunk_budget) {
153            to_write = file->chunk_budget;
154        }
155        BDBG_MSG((">writing [%u/%u] (%u/%u/%u) %lx", file->chunk, (unsigned)result, (unsigned)to_write, (unsigned)length, (unsigned)file->chunk_budget, (unsigned long)buf));
156        rc = file->data->data->write(file->data->data, buf, to_write);
157        BDBG_MSG(("<writing [%u/%u] (%u/%u/%u) %lx->%d", file->chunk, (unsigned)result, (unsigned)to_write, (unsigned)length, (unsigned)file->chunk_budget, (unsigned long)buf, (int)rc));
158        if (rc<=0) {
159            if  (result==0) {
160                result = rc; /* propagate error */
161            }
162            break;
163        }
164        result += rc;
165        length -= (size_t) rc;
166        BDBG_ASSERT((size_t)rc <= file->chunk_budget);
167        file->chunk_budget -=  (size_t)rc;
168        buf = (const uint8_t*)buf + rc;
169    }
170    return result;
171}
172
173static off_t
174chunk_trim(bfile_io_write_t fd, off_t trim_pos)
175{
176    BSTD_UNUSED(fd);
177    BSTD_UNUSED(trim_pos);
178    return 0;
179}
180
181struct bfile_out_chunk {
182    struct NEXUS_FileRecord self;
183    struct bfile_io_write_chunk data;
184    NEXUS_FileRecordHandle index; /* index file */
185};
186
187
188static void
189chunk_close_out(NEXUS_FileRecordHandle f)
190{
191    struct bfile_out_chunk *file =  (struct bfile_out_chunk *)f;
192
193    if (file->data.data) {
194        NEXUS_FileRecord_Close(file->data.data);
195    }
196    file->index->close(file->index);
197    BKNI_Free(file);
198    return;
199}
200
201
202NEXUS_FileRecordHandle
203NEXUS_ChunkedFileRecord_Open(const char *fname, const char *indexname, const NEXUS_ChunkedFileRecordOpenSettings *pSettings)
204{
205    struct bfile_out_chunk *file;
206    char name[B_MAX_FILE_LEN];
207    NEXUS_ChunkedFileRecordOpenSettings openSettings;
208
209    file = BKNI_Malloc(sizeof(*file));
210    if (!file) {
211        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
212        return NULL;
213    }
214    if ( NULL == pSettings )
215    {
216        NEXUS_ChunkedFileRecord_GetDefaultOpenSettings(&openSettings);
217        pSettings = &openSettings;
218    }
219    file->data.settings = *pSettings;
220    BKNI_Snprintf(file->data.base_name, sizeof(file->data.base_name), "%s", fname); /* dirty strcpy */ 
221    file->data.chunk = B_FIRST_CHUNK - 1;
222    file->data.data = NULL;
223    file->data.chunk_budget = 0; /* it would trigger open of data file on first call to write */
224    get_chunk_name(name, file->data.base_name, file->data.chunk);
225    file->data.open_out = NEXUS_FileRecord_OpenPosix; /* hard-coded, this may be exposed later if needed */
226    file->index = file->data.open_out(name, indexname);
227    if (!file->index) {
228        BKNI_Free(file);
229        return NULL;
230    }
231    /* wire things together */
232    file->self.index = file->index->index;
233    file->self.close = chunk_close_out;
234    file->data.self = *file->index->data;
235    file->data.self.write = chunk_write;
236    file->data.self.trim = chunk_trim;
237    file->self.data = &file->data.self;
238    return &file->self;
239}
240
241struct bfile_io_read_chunk {
242    struct bfile_io_read self;
243    NEXUS_FilePlayHandle data; /* current data file */
244    unsigned chunk; /* current chunk */
245    size_t  chunk_budget; /* number of bytes left in the chunk */
246    NEXUS_FilePlayHandle (*open_in)(const char *fname, const char *indexname);
247    char base_name[B_MAX_FILE_LEN];
248    off_t cur_pos;
249    struct {
250      unsigned last_chunk;
251      off_t last_chunk_begin;
252      NEXUS_FilePlayHandle last_data; /* cached file for last chunk */
253    } size;
254    NEXUS_ChunkedFilePlayOpenSettings settings;
255};
256
257
258static NEXUS_FilePlayHandle
259chunk_read_open(const struct bfile_io_read_chunk *file, unsigned chunk)
260{
261    char name[B_MAX_FILE_LEN];
262    NEXUS_FilePlayHandle data;
263   
264    get_chunk_name(name, file->base_name, chunk);
265    BDBG_MSG((">read opening %s", name));
266    data = file->open_in(name, NULL);
267    BDBG_MSG(("<read opening %s %#x", name, (unsigned)data));
268    return data;
269}
270
271static ssize_t
272chunk_read(bfile_io_read_t fd, void *buf_, size_t length)
273{
274    struct bfile_io_read_chunk *file = (struct bfile_io_read_chunk *) fd;
275    ssize_t result;
276    void *buf = buf_;
277
278    BDBG_MSG((">read %#x", (unsigned)fd));
279    for(result=0;length>0;) {
280        size_t to_read = length;
281        ssize_t rc;
282
283        if (file->chunk_budget==0) { /* time to open new file */
284            file->chunk++;
285            if(file->data) { 
286                BDBG_MSG(("read closing %#x", (unsigned)file->data));
287                NEXUS_FilePlay_Close(file->data);
288            }
289            file->data = chunk_read_open(file, file->chunk);
290            file->chunk_budget = file->settings.chunkSize;
291        }
292        if (!file->data) { /* if file isn't open, return EOF */
293            break;
294        }
295
296        if (to_read>file->chunk_budget) {
297            to_read = file->chunk_budget;
298        }
299        BDBG_MSG((">reading [%u/%u:%u] (%u/%u/%u) %#lx", (unsigned)result, file->chunk, (unsigned)file->cur_pos, (unsigned)to_read, (unsigned)length, (unsigned)file->chunk_budget, (unsigned long)buf));
300        rc = file->data->file.data->read(file->data->file.data, buf, to_read);
301        BDBG_MSG(("<reading [%u/%u:%u] (%u/%u/%u) %#lx->%d", (unsigned)result, file->chunk, (unsigned)file->cur_pos, (unsigned)to_read, (unsigned)length, (unsigned)file->chunk_budget, (unsigned long)buf, (int)rc));
302        if (rc<=0) {
303            if  (result==0) {
304                result = rc; /* propagate error */
305            }
306            break;
307        }
308        result += rc;
309        length -= (size_t) rc;
310        BDBG_ASSERT((size_t)rc <= file->chunk_budget);
311        file->chunk_budget -=  (size_t)rc;
312        file->cur_pos += (off_t)rc;
313        if ((size_t)rc<to_read) { /* if we read less than asked, return right the way */
314            break;
315        }
316        buf = (uint8_t *)buf + rc;
317    }
318    BDBG_MSG(("<read %d", (int)result));
319    return result;
320}
321
322
323static int
324chunk_bounds(bfile_io_read_t fd, off_t *first, off_t *last)
325{
326    struct bfile_io_read_chunk *file = (struct bfile_io_read_chunk *) fd;
327    NEXUS_FilePlayHandle data;
328    off_t size;
329
330    *first = 0;
331
332    BDBG_MSG((">bounds %#x", (unsigned)fd));
333
334    /* we assume that file only grows, and changes to new chunk at fixed
335       offset, also that there are now stale files in the directory */
336    for(;;) {
337        if (!file->size.last_data) {
338            data = chunk_read_open(file, file->size.last_chunk);
339        } else {
340            data = file->size.last_data;
341        }
342        if (data==NULL) {
343            BDBG_MSG(("<bounds last %u", (unsigned)file->size.last_chunk_begin));
344            *last = file->size.last_chunk_begin;
345            return 0;
346        }
347        data->file.data->bounds(data->file.data, first, &size);
348        file->size.last_data = data;
349        if (size!=file->settings.chunkSize) {
350            BDBG_MSG(("<bounds %u", (unsigned)(file->size.last_chunk_begin+size)));
351            *last = file->size.last_chunk_begin+size;
352            return 0;
353        }
354        /* advance to the next file */
355        data->file.close(data);
356        file->size.last_data = NULL;
357        file->size.last_chunk_begin += size;
358        file->size.last_chunk ++;
359        BDBG_MSG(("<bounds next %u", file->size.last_chunk));
360    }
361    *last = 0;
362    return 0;
363}
364
365static off_t
366chunk_seek(bfile_io_read_t fd, off_t offset, int whence)
367{
368    struct bfile_io_read_chunk *file = (struct bfile_io_read_chunk *) fd;
369    NEXUS_FilePlayHandle data=NULL;
370    unsigned dest_chunk;
371    off_t off,size;
372
373
374    /* same assumptions as in chunk_size */
375
376    /* we might need to serialize with read, however because only not
377     * serialized call is seek(0,SEEK_CUR) we shall be safe in most cases,
378     * so leave it for now */
379
380    BDBG_MSG((">seek %#x %lld %d", (unsigned)fd, offset, whence));
381    chunk_bounds(fd, &off, &size);
382
383    switch(whence) {
384    case SEEK_CUR:
385        offset = file->cur_pos + offset;
386        break;
387    case SEEK_END:
388        offset = size + offset;
389        break;
390    case SEEK_SET:
391        break;
392    default:
393        BDBG_ERR(("unknown seek whence %d", whence));
394        return -1;
395    }
396    if (offset == file->cur_pos) {
397        return offset;
398    }
399    if (offset < 0 || offset >= size) {
400        BDBG_WRN(("<seek out out bounds 0..%d..%d", (int)offset, (int)size));
401        return -1;
402    }
403    /* we don't use 64 bit mult and divide because they are known to be buggy */
404    for(dest_chunk=B_FIRST_CHUNK,off=0;offset-off>(off_t)file->settings.chunkSize;off+=file->settings.chunkSize) {
405        dest_chunk++;
406    }
407    /* we know chunk at this point */
408    if (dest_chunk == file->chunk) {
409        /* use already opened file */
410        data = file->data;
411    } else {
412        data = chunk_read_open(file, dest_chunk);
413    }
414    if (data==NULL) {
415        if (off == offset) { /* try to open next time */
416            file->chunk_budget = 0 ;
417            off = 0;
418            goto done;
419        } else { /* file was lost */
420            BDBG_WRN(("<seek %u -> error", (unsigned)offset));
421            return -1;
422        }
423    }
424    off = offset - off;
425    off = data->file.data->seek(data->file.data, off, SEEK_SET);
426    file->chunk_budget = file->settings.chunkSize - off;
427done:
428    if (file->data &&  data != file->data ) {
429        /* close old file */
430        file->data->file.close(file->data);
431    }
432    file->data = data;
433    file->chunk = dest_chunk;
434    file->cur_pos = offset;
435    BDBG_MSG(("<seek %u -> %u:[%u/%u]", (unsigned)offset, file->chunk, file->chunk_budget, (unsigned)off));
436    return offset;
437}
438
439struct bfile_in_chunk {
440    struct NEXUS_FilePlay self;
441    struct bfile_io_read_chunk data;
442    struct NEXUS_FilePlay *index;
443};
444
445static void
446chunk_close_in(NEXUS_FilePlayHandle f)
447{
448    struct bfile_in_chunk *file =  (struct bfile_in_chunk *)f;
449
450    if (file->data.data) {
451        file->data.data->file.close(file->data.data);
452    }
453    if (file->data.size.last_data) {
454        file->data.size.last_data->file.close(file->data.size.last_data);
455    }
456    if (file->index) {
457        file->index->file.close(file->index);
458    }
459    BKNI_Free(file);
460    return;
461}
462
463NEXUS_FilePlayHandle
464NEXUS_ChunkedFilePlay_Open(const char *fname, const char *indexname, const NEXUS_ChunkedFilePlayOpenSettings *pSettings)
465{
466    struct bfile_in_chunk *file;
467    char name[B_MAX_FILE_LEN];
468    NEXUS_ChunkedFilePlayOpenSettings openSettings;
469
470    if (!fname) {
471        BERR_TRACE(NEXUS_INVALID_PARAMETER);
472        return NULL;
473    }
474
475    file = BKNI_Malloc(sizeof(*file));
476    if (!file) {
477        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
478        return NULL;
479    }
480    if ( NULL == pSettings )
481    {
482        NEXUS_ChunkedFilePlay_GetDefaultOpenSettings(&openSettings);
483        pSettings = &openSettings;
484    }
485    file->data.settings = *pSettings;
486    /*bplayback_file_init(&file->self);*/
487
488    BKNI_Snprintf(file->data.base_name, sizeof(file->data.base_name), "%s", fname); /* dirty strcpy */ 
489    file->data.chunk = B_FIRST_CHUNK - 1;
490    file->data.data = NULL;
491    file->data.chunk_budget = 0; /* it would trigger open of data file on first call to write */
492    file->data.cur_pos = 0;
493    file->data.size.last_chunk = B_FIRST_CHUNK;
494    file->data.size.last_chunk_begin = 0;
495    file->data.size.last_data = NULL;
496    get_chunk_name(name, file->data.base_name, file->data.chunk);
497    file->data.open_in = NEXUS_FilePlay_OpenPosix;
498
499    file->index = file->data.open_in(name, indexname);
500    if (!file->index) {
501        BKNI_Free(file);
502        return NULL;
503    }
504    /* wire things together */
505    file->self.file.index = file->index->file.index;
506    file->self.file.close = chunk_close_in;
507    file->data.self = *file->index->file.data;
508    file->data.self.read = chunk_read;
509    file->data.self.seek = chunk_seek;
510    file->data.self.bounds = chunk_bounds;
511    file->self.file.data = &file->data.self;
512    return &file->self;
513}
514
Note: See TracBrowser for help on using the repository browser.