diff --git a/libisoburn/trunk/libisoburn/data_source.c b/libisoburn/trunk/libisoburn/data_source.c index f478265f..ccb83caf 100644 --- a/libisoburn/trunk/libisoburn/data_source.c +++ b/libisoburn/trunk/libisoburn/data_source.c @@ -1,7 +1,7 @@ /* data source for libisoburn. - Copyright 2007 - 2010 Vreixo Formoso Lopes + Copyright 2007 - 2012 Vreixo Formoso Lopes and Thomas Schmitt Provided under GPL version 2 or later. */ @@ -33,17 +33,7 @@ #include "isoburn.h" -/* Cached reading of image tree data */ -/* Multi tile: 32 * 64 kB */ - -/* The size of a single tile. - Powers of 2 only ! Less than 16 makes not much sense. -*/ -#define Libisoburn_tile_blockS 32 - -/* The number of tiles in the cache -*/ -#define Libisoburn_cache_tileS 32 +/* Cached reading of image tree data by multiple tiles */ /* Debugging only: This reports cache loads on stderr. @@ -52,7 +42,7 @@ struct isoburn_cache_tile { - char cache_data[Libisoburn_tile_blockS * 2048]; + char *cache_data; uint32_t cache_lba; uint32_t last_error_lba; uint32_t last_aligned_error_lba; @@ -62,7 +52,9 @@ struct isoburn_cache_tile { struct isoburn_cached_drive { struct burn_drive *drive; - struct isoburn_cache_tile tiles[Libisoburn_cache_tileS]; + struct isoburn_cache_tile **tiles; + int num_tiles; + int tile_blocks; int current_age; /** @@ -92,7 +84,7 @@ int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) off_t count; uint32_t aligned_lba; char msg[80]; - struct isoburn_cache_tile *tiles; + struct isoburn_cache_tile **tiles; struct isoburn_cached_drive *icd; if(src == NULL || buffer == NULL) @@ -117,7 +109,7 @@ int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) return ISO_ASSERT_FAILURE; } - tiles = (struct isoburn_cache_tile *) icd->tiles; + tiles = icd->tiles; if(icd->displacement_sign == 1) { if(lba + icd->displacement < lba) { @@ -132,12 +124,13 @@ address_rollover:; lba -= icd->displacement; } - aligned_lba= lba & ~(Libisoburn_tile_blockS - 1); + aligned_lba= lba & ~(icd->tile_blocks - 1); - for(i=0; inum_tiles; i++) { + if(aligned_lba == tiles[i]->cache_lba && + tiles[i]->cache_lba != 0xffffffff) { + (tiles[i]->cache_hits)++; + memcpy(buffer, tiles[i]->cache_data + (lba - aligned_lba) * 2048, 2048); count= 2048; ds_inc_age(icd, i, 0); return 1; @@ -147,37 +140,37 @@ address_rollover:; /* find oldest tile */ oldest_age= Libisoburn_max_agE; oldest= 0; - for(i= 0; inum_tiles; i++) { + if(tiles[i]->cache_lba == 0xffffffff) { oldest= i; break; } - if(tiles[i].ageage < oldest_age) { + oldest_age= tiles[i]->age; oldest= i; } } - tiles[oldest].cache_lba= 0xffffffff; /* invalidate cache */ - if(tiles[oldest].last_aligned_error_lba == aligned_lba) { + tiles[oldest]->cache_lba= 0xffffffff; /* invalidate cache */ + if(tiles[oldest]->last_aligned_error_lba == aligned_lba) { ret = 0; } else { ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048, - (char *) tiles[oldest].cache_data, - Libisoburn_tile_blockS * 2048, &count, 2); + (char *) tiles[oldest]->cache_data, + icd->tile_blocks * 2048, &count, 2); } if (ret <= 0 ) { - tiles[oldest].last_aligned_error_lba = aligned_lba; + tiles[oldest]->last_aligned_error_lba = aligned_lba; /* Read-ahead failure ? Try to read 2048 directly. */ - if(tiles[oldest].last_error_lba == lba) + if(tiles[oldest]->last_error_lba == lba) ret = 0; else ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer, 2048, &count, 0); if (ret > 0) return 1; - tiles[oldest].last_error_lba = lba; + tiles[oldest]->last_error_lba = lba; sprintf(msg, "ds_read_block(%lu) returns %lX", (unsigned long) lba, (unsigned long) ret); isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "DEBUG", 0); @@ -186,14 +179,14 @@ address_rollover:; #ifdef Libisoburn_read_cache_reporT fprintf(stderr, "Tile %2.2d : After %3d hits, new load from %8x , count= %d\n", - oldest, tiles[oldest].cache_hits, aligned_lba, (int) count); + oldest, tiles[oldest]->cache_hits, aligned_lba, (int) count); #endif - tiles[oldest].cache_lba= aligned_lba; - tiles[oldest].cache_hits= 1; + tiles[oldest]->cache_lba= aligned_lba; + tiles[oldest]->cache_hits= 1; ds_inc_age(icd, oldest, 0); - memcpy(buffer, tiles[oldest].cache_data + (lba - aligned_lba) * 2048, 2048); + memcpy(buffer, tiles[oldest]->cache_data + (lba - aligned_lba) * 2048, 2048); count= 2048; return 1; @@ -212,11 +205,107 @@ static int ds_close(IsoDataSource *src) return 1; } + +static int isoburn_cache_tile_destroy(struct isoburn_cache_tile **o, + int flag) +{ + if (*o == NULL) + return(0); + if ((*o)->cache_data != NULL) + free((*o)->cache_data); + free(*o); + *o = NULL; + return(1); +} + + +static int isoburn_cache_tile_new(struct isoburn_cache_tile **o, + int tile_blocks, int flag) +{ + struct isoburn_cache_tile *t; + + *o = t = calloc(1, sizeof(struct isoburn_cache_tile)); + if (t == NULL) + goto fail; + t->cache_data = NULL; + t->cache_lba = 0xffffffff; + t->cache_hits = 0; + t->last_error_lba = 0xffffffff; + t->last_aligned_error_lba = 0xffffffff; + t->age= 0; + + t->cache_data = calloc(1, tile_blocks * 2048); + if (t->cache_data == NULL) + goto fail; + + return(1); +fail:; + isoburn_cache_tile_destroy(o, 0); + return(-1); +} + + +static int isoburn_cached_drive_destroy(struct isoburn_cached_drive **o, + int flag) +{ + struct isoburn_cached_drive *c; + int i; + + if (*o == NULL) + return(0); + c= *o; + if (c->tiles != NULL) { + for (i = 0; i < c->num_tiles; i++) + isoburn_cache_tile_destroy(&(c->tiles[i]), 0); + free(c->tiles); + } + free(c); + *o= NULL; + return(1); +} + + +static int isoburn_cached_drive_new(struct isoburn_cached_drive **o, + struct burn_drive *d, int cache_tiles, + int tile_blocks, int flag) +{ + struct isoburn_cached_drive *icd; + int i, ret; + + *o = icd = calloc(1,sizeof(struct isoburn_cached_drive)); + if (o == NULL) + return(-1); + icd->drive = d; + icd->tiles = NULL; + icd->num_tiles = cache_tiles; + icd->tile_blocks = tile_blocks; + icd->current_age = 0; + icd->displacement = 0; + icd->displacement_sign = 0; + + icd->tiles = calloc(1, sizeof(struct isoburn_cache_tile *) * icd->num_tiles); + if (icd->tiles == NULL) + goto fail; + for (i = 0; i < icd->num_tiles; i++) { + ret = isoburn_cache_tile_new(&(icd->tiles[i]), icd->tile_blocks, 0); + if (ret <= 0) + goto fail; + } + return(1); +fail:; + isoburn_cached_drive_destroy(o, 0); + return(-1); +} + + static void ds_free_data(IsoDataSource *src) { - /* nothing to do */; - if(src->data != NULL) - free(src->data); + struct isoburn_cached_drive *icd; + + if(src->data != NULL) { + icd= (struct isoburn_cached_drive *) src->data; + isoburn_cached_drive_destroy(&icd, 0); + } src->data= NULL; } @@ -234,37 +323,33 @@ int isoburn_data_source_shutdown(IsoDataSource *src, int flag) IsoDataSource *isoburn_data_source_new(struct burn_drive *d, - uint32_t displacement, int displacement_sign) + uint32_t displacement, int displacement_sign, + int cache_tiles, int tile_blocks) { - IsoDataSource *ret; + IsoDataSource *src; struct isoburn_cached_drive *icd= NULL; - int i; + int ret; if (d==NULL) return NULL; - ret = malloc(sizeof(IsoDataSource)); - icd = calloc(1,sizeof(struct isoburn_cached_drive)); - if (ret == NULL || icd == NULL) + src = malloc(sizeof(IsoDataSource)); + if (src == NULL) + return NULL; + ret = isoburn_cached_drive_new(&icd, d, cache_tiles, tile_blocks, 0); + if (ret <= 0) { + free(src); return NULL; - ret->version = 0; - ret->refcount = 1; - ret->read_block = ds_read_block; - ret->open = ds_open; - ret->close = ds_close; - ret->free_data = ds_free_data; - ret->data = icd; - icd->drive = d; - icd->current_age= 0; - for(i= 0; itiles[i].cache_lba = 0xffffffff; - icd->tiles[i].cache_hits = 0; - icd->tiles[i].last_error_lba = 0xffffffff; - icd->tiles[i].last_aligned_error_lba = 0xffffffff; - icd->tiles[i].age= 0; } + src->version = 0; + src->refcount = 1; + src->read_block = ds_read_block; + src->open = ds_open; + src->close = ds_close; + src->free_data = ds_free_data; + src->data = icd; icd->displacement = displacement; icd->displacement_sign = displacement_sign; - return ret; + return src; } @@ -274,11 +359,11 @@ static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag) (icd->current_age)++; if(icd->current_age>=Libisoburn_max_agE) { /* reset all ages (allow waste) */ - for(i= 0; itiles)[i].age= 0; + for(i = 0; i < icd->num_tiles; i++) + (icd->tiles)[i]->age= 0; icd->current_age= 1; } - (icd->tiles)[idx].age= icd->current_age; + (icd->tiles)[idx]->age= icd->current_age; return(1); } diff --git a/libisoburn/trunk/libisoburn/isoburn.c b/libisoburn/trunk/libisoburn/isoburn.c index fcbc67f8..a7520d66 100644 --- a/libisoburn/trunk/libisoburn/isoburn.c +++ b/libisoburn/trunk/libisoburn/isoburn.c @@ -776,6 +776,8 @@ int isoburn_ropt_new(struct isoburn_read_opts **new_o, int flag) "Cannot allocate memory for read options", 0, "FATAL", 0); return(-1); } + o->cache_tiles= Libisoburn_default_cache_tileS; + o->cache_tile_blocks= Libisoburn_default_tile_blockS; o->norock= 0; o->nojoliet= 0; o->noiso1999= 1; @@ -812,6 +814,59 @@ int isoburn_ropt_destroy(struct isoburn_read_opts **o, int flag) } +int isoburn_ropt_set_data_cache(struct isoburn_read_opts *o, + int cache_tiles, int tile_blocks, int flag) +{ + int i; + char msg[80]; + + if(cache_tiles < 1) { + isoburn_msgs_submit(NULL, 0x00060000, + "Requested number of data cache tiles is too small (< 1)", + 0, "SORRY", 0); + return(0); + } + if(((double) cache_tiles) * ((double) tile_blocks) + > (double) Libisoburn_cache_max_sizE) { + sprintf(msg, "Requested size of data cache exceeds limit of %.f blocks", + (double) Libisoburn_cache_max_sizE); + isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "SORRY", 0); + return(0); + } + for(i = 1; i <= Libisoburn_cache_max_sizE; i = i << 1) + if(i == tile_blocks) + break; + if(i > Libisoburn_cache_max_sizE) { + isoburn_msgs_submit(NULL, 0x00060000, + "Requested number of blocks per data cache tiles is not a power of 2", + 0, "SORRY", 0); + return(0); + } + if(o != NULL) { + o->cache_tiles= cache_tiles; + o->cache_tile_blocks= tile_blocks; + } + return(1); +} + + +int isoburn_ropt_get_data_cache(struct isoburn_read_opts *o, + int *cache_tiles, int *tile_blocks, + int *set_flag, int flag) +{ + if((flag & 1) || o == NULL) { + *cache_tiles= Libisoburn_default_cache_tileS; + *tile_blocks= Libisoburn_default_tile_blockS; + *set_flag= 0; + return(1); + } + *cache_tiles= o->cache_tiles; + *tile_blocks= o->cache_tile_blocks; + *set_flag= 0; + return(1); +} + + int isoburn_ropt_set_extensions(struct isoburn_read_opts *o, int ext) { o->norock= !!(ext&1); diff --git a/libisoburn/trunk/libisoburn/isoburn.h b/libisoburn/trunk/libisoburn/isoburn.h index 826b45ae..ef51c5f5 100644 --- a/libisoburn/trunk/libisoburn/isoburn.h +++ b/libisoburn/trunk/libisoburn/isoburn.h @@ -263,7 +263,19 @@ int isoburn_get_msc2(struct isoburn *o, */ IsoDataSource * isoburn_data_source_new(struct burn_drive *d, - uint32_t displacement, int displacement_sign); + uint32_t displacement, int displacement_sign, + int cache_tiles, int tile_blocks); + +/** Default settings for above cache_tiles, tile_blocks in newly created + struct isoburn_read_opts. +*/ +#define Libisoburn_default_cache_tileS 32 +#define Libisoburn_default_tile_blockS 32 + +/** Maximum size of the cache in 2 kB blocks (1 GB) +*/ +#define Libisoburn_cache_max_sizE (1024 * 512) + /** Disable read capabilities of a data source which was originally created by isoburn_data_source_new(). After this any attempt to read will yield @@ -298,6 +310,9 @@ int isoburn_root_defaults(IsoImage *image, int flag); minor correction only.) */ struct isoburn_read_opts { + int cache_tiles; /* number of cache tiles */ + int cache_tile_blocks; + unsigned int norock:1; /*< Do not read Rock Ridge extensions */ unsigned int nojoliet:1; /*< Do not read Joliet extensions */ unsigned int noiso1999:1; /*< Do not read ISO 9660:1999 enhanced tree */ diff --git a/libisoburn/trunk/libisoburn/isofs_wrap.c b/libisoburn/trunk/libisoburn/isofs_wrap.c index 6e2442b9..ec48a91c 100644 --- a/libisoburn/trunk/libisoburn/isofs_wrap.c +++ b/libisoburn/trunk/libisoburn/isofs_wrap.c @@ -218,8 +218,6 @@ create_blank_image:; {ret= -4; goto ex;} } - memset((char *) &ropts, 0, sizeof(ropts)); - ret = isoburn_disc_get_msc1(d, &int_num); if (ret <= 0) {ret= -2; goto ex;} @@ -284,11 +282,12 @@ displacement_rollover:; iso_read_opts_load_system_area(ropts, 1); ds = isoburn_data_source_new(d, read_opts->displacement, - read_opts->displacement_sign); + read_opts->displacement_sign, + read_opts->cache_tiles, read_opts->cache_tile_blocks); if (ds == NULL) { isoburn_report_iso_error(ret, "Cannot create IsoDataSource object", 0, "FATAL", 0); - goto ex; + ret= -1; goto ex; } if(o->iso_data_source!=NULL) iso_data_source_unref(o->iso_data_source); @@ -302,6 +301,7 @@ displacement_rollover:; ret = iso_image_import(o->image, ds, ropts, &features); iso_tree_set_report_callback(o->image, NULL); iso_read_opts_free(ropts); + ropts= NULL; if (ret < 0) { isoburn_report_iso_error(ret, "Cannot import image", 0, "FAILURE", 0); @@ -322,6 +322,8 @@ displacement_rollover:; ex:; if(msg != NULL) free(msg); + if(ropts != NULL) + iso_read_opts_free(ropts); return(ret); } diff --git a/libisoburn/trunk/libisoburn/libisoburn.h b/libisoburn/trunk/libisoburn/libisoburn.h index 6ef3c50e..b8896f5b 100644 --- a/libisoburn/trunk/libisoburn/libisoburn.h +++ b/libisoburn/trunk/libisoburn/libisoburn.h @@ -759,6 +759,56 @@ int isoburn_ropt_new(struct isoburn_read_opts **o, int flag); */ int isoburn_ropt_destroy(struct isoburn_read_opts **o, int flag); +/** Sets the size and granularity of the cache which libisoburn provides to + libisofs for reading of ISO image data. This cache consists of several + tiles which are buffers of a given size. The ISO image is divided into + virtual tiles of that size. A cache tile may hold an in-memory copy + of such a virtual image tile. + When libisofs requests to read a block, then first the cache is inquired + whether it holds that block. If not, then the block is read via libburn + together with its neighbors in their virtual image tile into a free + cache tile. If no cache tile is free, then the one will be re-used which + has the longest time of not being hit by a read attempt. + + A larger cache might speed up image loading by reducing the number of + libburn read calls on the directory tree. It might also help with + reading the content of many small files, if for some reason it is not an + option to sort access by LBA. + Caching will not provide much benefit with libburn "stdio:" drives, + because the operating system is supposed to provide the same speed-up + in a more flexible way. + + @since 1.2.2 + @param o The option set to work on. + It is permissible to submit NULL in order to just + have the parameters tested. + @param cache_tiles Number of tiles in the cache. Not less than 1. + Default is 32. + @param tile_blocks Number of blocks per tile. Must be a power of 2. + Default is 32. + cache_tiles * tile_blocks * 2048 must not exceed + 1073741824 (= 1 GiB). + @param flag Bitfield for control purposes. Unused yet. Submit 0. + @return <=0 error , >0 ok +*/ +int isoburn_ropt_set_data_cache(struct isoburn_read_opts *o, + int cache_tiles, int tile_blocks, int flag); + +/** Inquire the current settings of isoburn_set_data_cache(). + @since 1.2.2 + @param o The option set to work on. + NULL has the same effect as flag bit0. + @param cache_tiles Will return the number of tiles in the cache. + @param tile_blocks Will return the number of blocks per tile. + @param set_flag Will return control bits. None are defined yet. + @param flag Bitfield for control purposes + bit0= return default values rather than current ones + @return <=0 error , >0 reply is valid +*/ +int isoburn_ropt_get_data_cache(struct isoburn_read_opts *o, + int *cache_tiles, int *tile_blocks, + int *set_flag, int flag); + /** Which existing ISO 9660 extensions in the image to read or not to read. Whether to read the content of an existing image at all. diff --git a/libisoburn/trunk/libisoburn/libisoburn.ver b/libisoburn/trunk/libisoburn/libisoburn.ver index b90d5c37..d01ee218 100644 --- a/libisoburn/trunk/libisoburn/libisoburn.ver +++ b/libisoburn/trunk/libisoburn/libisoburn.ver @@ -74,6 +74,7 @@ isoburn_read_image; isoburn_read_iso_head; isoburn_ropt_destroy; isoburn_ropt_get_auto_incharset; +isoburn_ropt_get_data_cache; isoburn_ropt_get_default_dirperms; isoburn_ropt_get_default_perms; isoburn_ropt_get_displacement; @@ -82,6 +83,7 @@ isoburn_ropt_get_input_charset; isoburn_ropt_get_size_what; isoburn_ropt_new; isoburn_ropt_set_auto_incharset; +isoburn_ropt_set_data_cache; isoburn_ropt_set_default_dirperms; isoburn_ropt_set_default_perms; isoburn_ropt_set_displacement; diff --git a/libisoburn/trunk/xorriso/xorriso_timestamp.h b/libisoburn/trunk/xorriso/xorriso_timestamp.h index 85e76d8e..7b912e44 100644 --- a/libisoburn/trunk/xorriso/xorriso_timestamp.h +++ b/libisoburn/trunk/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2012.03.10.153518" +#define Xorriso_timestamP "2012.03.11.162050"