131
131
least as large as the fixed overhead of the compressor plus the
132
132
decompressor, plus the expected compressed size of a block that size.
134
static const long COMPRESSION_THRESHOLD = 32000000;
134
static const long COMPRESSION_THRESHOLD = 500000000; /* 0.5 Gb for host machines */
136
136
#define NEED_TO_COMPRESS(f)\
137
137
((f)->ok_to_compress && (f)->total_space > COMPRESSION_THRESHOLD)
139
/* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8) */
140
#define GET_NUM_RAW_BUFFERS( f ) \
141
max(f->log_length/MEMFILE_DATA_SIZE/32, 8)
139
/* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8, no more than 64) */
140
#define GET_NUM_RAW_BUFFERS( f ) \
141
min(64, max(f->log_length/MEMFILE_DATA_SIZE/32, 8))
143
143
#define MALLOC(f, siz, cname)\
144
144
(void *)gs_alloc_bytes((f)->data_memory, siz, cname)
225
226
clist_file_ptr /*MEMFILE * */ * pf,
226
227
gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
231
/* We don't implement reopening an existing file. */
232
if (fname[0] != 0 || fmode[0] != 'w') {
233
code = gs_note_error(gs_error_invalidfileaccess);
232
*pf = NULL; /* in case we have an error */
234
/* fname[0] == 0 if this is not reopening */
235
/* memfile file names begin with a flag byte == 0xff */
236
if (fname[0] == '\377' || fmode[0] == 'r') {
237
MEMFILE *base_f = NULL;
239
/* reopening an existing file. */
240
code = sscanf(fname+1, "0x%x", &base_f);
242
gs_note_error(gs_error_ioerror);
245
if (fmode[0] == 'w') {
246
/* Reopen an existing file for 'write' */
247
/* Check first to make sure that we have exclusive access */
248
if (base_f->openlist != NULL) {
249
code = gs_note_error(gs_error_ioerror);
252
f = base_f; /* use the file */
255
/* Reopen an existing file for 'read' */
256
/* We need to 'clone' this memfile so that each reader instance */
257
/* will be able to maintain it's own 'state' */
258
f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
259
"memfile_fopen_instance(MEMFILE)");
261
eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
262
code = gs_note_error(gs_error_VMerror);
265
memcpy(f, base_f, sizeof(MEMFILE));
267
f->data_memory = data_mem;
268
f->compress_state = 0; /* Not used by reader instance */
269
f->decompress_state = 0; /* make clean for GC, or alloc'n failure */
270
f->reservePhysBlockChain = NULL;
271
f->reservePhysBlockCount = 0;
272
f->reserveLogBlockChain = NULL;
273
f->reserveLogBlockCount = 0;
274
f->openlist = base_f->openlist;
275
base_f->openlist = f; /* link this one in to the base memfile */
276
f->base_memfile = base_f;
281
if (f->log_head->phys_blk->data_limit != NULL) {
282
/* The file is compressed, so we need to copy the logical block */
283
/* list so that it is unique to this instance, and initialize */
284
/* the decompressor. */
285
LOG_MEMFILE_BLK *log_block, *new_log_block;
287
int num_log_blocks = (f->log_length + MEMFILE_DATA_SIZE - 1) / MEMFILE_DATA_SIZE;
288
const stream_state *decompress_proto = clist_decompressor_state(NULL);
289
const stream_template *decompress_template = decompress_proto->template;
291
new_log_block = MALLOC(f, num_log_blocks * sizeof(LOG_MEMFILE_BLK), "memfile_fopen" );
292
if (new_log_block == NULL)
293
code = gs_note_error(gs_error_VMerror);
295
/* copy the logical blocks to the new list just allocated */
296
for (log_block=f->log_head, i=0; log_block != NULL; log_block=log_block->link, i++) {
297
new_log_block[i].phys_blk = log_block->phys_blk;
298
new_log_block[i].phys_pdata = log_block->phys_pdata;
299
new_log_block[i].raw_block = NULL;
300
new_log_block[i].link = log_block->link == NULL ? NULL : new_log_block + i + 1;
302
f->log_head = new_log_block;
304
/* NB: don't need compress_state for reading */
305
f->decompress_state =
306
gs_alloc_struct(mem, stream_state, decompress_template->stype,
307
"memfile_open_scratch(decompress_state)");
308
if (f->decompress_state == 0) {
309
eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
310
code = gs_note_error(gs_error_VMerror);
313
memcpy(f->decompress_state, decompress_proto,
314
gs_struct_type_size(decompress_template->stype));
315
f->decompress_state->memory = mem;
316
if (decompress_template->set_defaults)
317
(*decompress_template->set_defaults) (f->decompress_state);
319
f->log_curr_blk = f->log_head;
320
memfile_get_pdata(f); /* set up the initial block */
237
/* There is no need to set fname in this implementation, */
238
/* but we do it anyway. */
239
fname[0] = (ok_to_compress ? 'a' : 'b');
325
fname[0] = 0; /* no file name yet */
242
326
f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
243
327
"memfile_open_scratch(MEMFILE)");
327
413
MEMFILE *const f = (MEMFILE *)cf;
329
/* We don't implement closing without deletion. */
331
return_error(gs_error_invalidfileaccess);
416
if (f->base_memfile) {
419
/* Here we need to delete this instance from the 'openlist' */
420
/* in case this file was opened for 'read' on a previously */
421
/* written file (base_memfile != NULL) */
422
for (prev_f = f->base_memfile; prev_f != NULL; prev_f = prev_f->openlist)
423
if (prev_f->openlist == f)
425
if (prev_f == NULL) {
426
eprintf1("Could not find 0x%x on memfile openlist\n", ((unsigned int)f));
427
return_error(gs_error_invalidfileaccess);
429
prev_f->openlist = f->openlist; /* link around the one being fclosed */
430
/* Now delete this MEMFILE reader instance */
431
/* NB: we don't delete 'base' instances until we delete */
432
/* If the file is compressed, free the logical blocks, but not */
433
/* the phys_blk info (that is still used by the base memfile */
434
if (f->log_head->phys_blk->data_limit != NULL) {
435
LOG_MEMFILE_BLK *tmpbp, *bp = f->log_head;
439
FREE(f, bp, "memfile_free_mem(log_blk)");
444
/* Free any internal compressor state. */
445
if (f->compressor_initialized) {
446
if (f->decompress_state->template->release != 0)
447
(*f->decompress_state->template->release) (f->decompress_state);
448
if (f->compress_state->template->release != 0)
449
(*f->compress_state->template->release) (f->compress_state);
450
f->compressor_initialized = false;
452
/* free the raw buffers */
453
while (f->raw_head != NULL) {
454
RAW_BUFFER *tmpraw = f->raw_head->fwd;
456
FREE(f, f->raw_head, "memfile_free_mem(raw)");
457
f->raw_head = tmpraw;
460
/* deallocate the memfile object proper */
461
gs_free_object(f->memory, f, "memfile_close_and_unlink(MEMFILE)");
466
/* If there are open read memfile structures, set them so that */
467
/* future accesses will return errors rather than causing SEGV */
469
/* TODO: do the cleanup rather than just giving an error */
470
eprintf1("Attempt to delete a memfile still open for read: 0x%0x\n", ((unsigned int)f));
471
return_error(gs_error_invalidfileaccess);
332
473
memfile_free_mem(f);
334
475
/* Free reserve blocks; don't do it in memfile_free_mem because */
960
1105
/* Free up memory that was allocated for the memfile */
961
1106
bp = f->log_head;
963
/******************************************************************
964
* The following was the original algorithm here. This algorithm has a bug:
965
* the second loop references the physical blocks again after they have been
967
******************************************************************/
969
#if 0 /**************** *************** */
972
/* Free the physical blocks that make up the compressed data */
973
PHYS_MEMFILE_BLK *pphys = (f->log_head)->phys_blk;
975
if (pphys->data_limit != NULL) {
976
/* the data was compressed, free the chain of blocks */
977
while (pphys != NULL) {
978
PHYS_MEMFILE_BLK *tmpphys = pphys->link;
980
FREE(f, pphys, "memfile_free_mem(pphys)");
985
/* free the logical blocks */
987
/* if this logical block was not compressed, free the phys_blk */
988
if (bp->phys_blk->data_limit == NULL) {
989
FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
992
FREE(f, bp, "memfile_free_mem(log_blk)");
996
#else /**************** *************** */
997
# if 1 /**************** *************** */
999
/****************************************************************
1000
* This algorithm is correct (we think).
1001
****************************************************************/
1003
1108
if (bp != NULL) {
1004
1109
/* Null out phys_blk pointers to compressed data. */
1005
1110
PHYS_MEMFILE_BLK *pphys = bp->phys_blk;
1033
/***********************************************************************
1034
* This algorithm appears to be both simpler and free of the bug that
1035
* occasionally causes the older one to reference freed blocks; but in
1036
* fact it can miss blocks, because the very last compressed logical block
1037
* can have spill into a second physical block, which is not referenced by
1038
* any logical block.
1039
***********************************************************************/
1041
# else /**************** *************** */
1044
PHYS_MEMFILE_BLK *prev_phys = 0;
1046
while (bp != NULL) {
1047
PHYS_MEMFILE_BLK *phys = bp->phys_blk;
1049
if (phys != prev_phys) {
1050
FREE(f, phys, "memfile_free_mem(phys_blk)");
1054
FREE(f, bp, "memfile_free_mem(log_blk)");
1059
# endif /**************** *************** */
1060
#endif /**************** *************** */
1062
1138
f->log_head = NULL;
1064
1140
/* Free any internal compressor state. */