Commit b42293cd authored by Thomas Schmitt's avatar Thomas Schmitt

New API calls isoburn_ropt_set_data_cache(), isoburn_ropt_get_data_cache()

parent 8f48b854
/*
data source for libisoburn.
Copyright 2007 - 2010 Vreixo Formoso Lopes <metalpain2002@yahoo.es>
Copyright 2007 - 2012 Vreixo Formoso Lopes <metalpain2002@yahoo.es>
and Thomas Schmitt <scdbackup@gmx.net>
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; i<Libisoburn_cache_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);
for (i = 0; i < icd->num_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; i<Libisoburn_cache_tileS; i++) {
if(tiles[i].cache_lba == 0xffffffff) {
for(i = 0; i < icd->num_tiles; i++) {
if(tiles[i]->cache_lba == 0xffffffff) {
oldest= i;
break;
}
if(tiles[i].age<oldest_age) {
oldest_age= tiles[i].age;
if(tiles[i]->age < 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; i<Libisoburn_cache_tileS; i++) {
icd->tiles[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; i<Libisoburn_cache_tileS; i++)
(icd->tiles)[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);
}
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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);
}
......
......@@ -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.
......
......@@ -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;
......
#define Xorriso_timestamP "2012.03.10.153518"
#define Xorriso_timestamP "2012.03.11.162050"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment