| 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 | |
|---|
| 72 | BDBG_MODULE(bfile_cache); |
|---|
| 73 | |
|---|
| 74 | #define BDBG_MSG_TRACE(x) /* BDBG_MSG(x) */ |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | void |
|---|
| 78 | bfile_segment_clear(bfile_segment *segment) |
|---|
| 79 | { |
|---|
| 80 | segment->start = -1; |
|---|
| 81 | segment->len = 0; |
|---|
| 82 | return; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | void |
|---|
| 86 | bfile_segment_set(bfile_segment *segment, off_t start, uint64_t len) |
|---|
| 87 | { |
|---|
| 88 | segment->start = start; |
|---|
| 89 | segment->len = len; |
|---|
| 90 | return; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | bool |
|---|
| 94 | bfile_segment_test(const bfile_segment *segment) |
|---|
| 95 | { |
|---|
| 96 | return segment->len>0 && segment->start>0; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | BDBG_OBJECT_ID(bfile_cache_t); |
|---|
| 100 | |
|---|
| 101 | struct 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 | |
|---|
| 114 | bfile_cache_t |
|---|
| 115 | bfile_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 | |
|---|
| 148 | void |
|---|
| 149 | bfile_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 | |
|---|
| 157 | void |
|---|
| 158 | bfile_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 | |
|---|
| 170 | void |
|---|
| 171 | bfile_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 | |
|---|
| 180 | int |
|---|
| 181 | bfile_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 | |
|---|
| 211 | const uint8_t * |
|---|
| 212 | bfile_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 | |
|---|
| 277 | int |
|---|
| 278 | bfile_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 | |
|---|
| 299 | bool |
|---|
| 300 | bfile_cache_is_file_error(bfile_cache_t cache) |
|---|
| 301 | { |
|---|
| 302 | return cache->file_error; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | void |
|---|
| 306 | bfile_cached_segment_shutdown(bfile_cached_segment *segment) |
|---|
| 307 | { |
|---|
| 308 | batom_accum_destroy(segment->accum); |
|---|
| 309 | return; |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | |
|---|
| 313 | void |
|---|
| 314 | bfile_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 | |
|---|
| 325 | uint64_t |
|---|
| 326 | bfile_cached_segment_tell(bfile_cached_segment *segment) |
|---|
| 327 | { |
|---|
| 328 | return segment->accum_offset + batom_cursor_pos(&segment->cursor); |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | void |
|---|
| 332 | bfile_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 | |
|---|
| 341 | static bfile_segment_async_result |
|---|
| 342 | b_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 | |
|---|
| 358 | static void |
|---|
| 359 | b_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 | |
|---|
| 377 | bfile_segment_async_result |
|---|
| 378 | bfile_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 | |
|---|
| 429 | bool |
|---|
| 430 | bfile_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 | |
|---|
| 476 | bool |
|---|
| 477 | bfile_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 | |
|---|
| 482 | bool |
|---|
| 483 | bfile_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 | |
|---|
| 488 | bool |
|---|
| 489 | bfile_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 | |
|---|