--- freem/src/global_bltin.c 2025/04/11 14:21:03 1.17 +++ freem/src/global_bltin.c 2025/04/11 16:23:18 1.18 @@ -1,5 +1,5 @@ /* - * $Id: global_bltin.c,v 1.17 2025/04/11 14:21:03 snw Exp $ + * $Id: global_bltin.c,v 1.18 2025/04/11 16:23:18 snw Exp $ * freem database engine * * @@ -24,6 +24,9 @@ * along with FreeM. If not, see . * * $Log: global_bltin.c,v $ + * Revision 1.18 2025/04/11 16:23:18 snw + * Avoid re-reading the same block consecutively when possible + * * Revision 1.17 2025/04/11 14:21:03 snw * Make all but one of the read/write calls in global_bltin use gbl_read_block or gbl_write_block * @@ -323,7 +326,7 @@ int gbl_write_header(global_handle *g, g return FALSE; } - if (g->locked == FALSE) gbl_lock (g, 1); + gbl_lock (g, 1); old_position = lseek (g->fd, 0, SEEK_CUR); lseek (g->fd, 0, SEEK_SET); @@ -333,7 +336,7 @@ int gbl_write_header(global_handle *g, g } lseek (g->fd, old_position, SEEK_SET); - if (g->locked == TRUE) gbl_unlock (g); + gbl_unlock (g); gbl_read_header (g, &g->header); @@ -445,9 +448,13 @@ short gbl_open(global_handle *g, short a } else { g->opened = TRUE; - result = gbl_read_header (g, &g->header); + result = gbl_read_header (g, &g->header); if (result == GBL_HDR_OK) { + /* initialize last_block_accessed cache */ + g->last_block_accessed = (char *) calloc (g->header.block_size, sizeof (char)); + NULLPTRCHK(g->last_block_accessed,"gbl_open"); + g->opened = TRUE; } else { @@ -479,6 +486,7 @@ short gbl_open(global_handle *g, short a int gbl_read_block(global_handle *g, unsigned long blocknum, char *block) { + struct stat gstat; unsigned long hdr_offset; hdr_offset = sizeof (global_header); @@ -486,13 +494,38 @@ int gbl_read_block(global_handle *g, uns return FALSE; } - gbl_lock (g, 1); - lseek (g->fd, hdr_offset + ((long) blocknum * (long) (g->header.block_size)), SEEK_SET); - read (g->fd, block, g->header.block_size); - g->last_block = blocknum; g->use_count++; - g->read_ops++; - gbl_unlock (g); + + fstat (g->fd, &gstat); + if (!g->locked) gbl_lock (g, 1); + + + if ((g->last_block == blocknum) && + (g->have_cached_block) && + (g->cached_block_num == blocknum) && + (gstat.st_mtime < g->last_read_time)) { + /* the global has not been modified since the last read; grab from memory */ + g->memory_reads++; + g->last_read_time = time (0L); + memcpy (block, g->last_block_accessed, g->header.block_size); + } + else { + /* have to go out to disk */ + lseek (g->fd, hdr_offset + ((long) blocknum * (long) (g->header.block_size)), SEEK_SET); + read (g->fd, block, g->header.block_size); + + /* update cache */ + memcpy (g->last_block_accessed, block, g->header.block_size); + g->have_cached_block = TRUE; + g->last_read_time = time (0L); + g->cached_block_num = blocknum; + + g->last_block = blocknum; + g->use_count++; + g->read_ops++; + } + + if (g->locked) gbl_unlock (g); return TRUE; } /* gbl_read_block() */ @@ -507,9 +540,7 @@ int gbl_write_block(global_handle *g, un return FALSE; } - if (!g->locked) { - gbl_lock (g, 1); - } + gbl_lock (g, 1); for (;;) { @@ -528,11 +559,8 @@ int gbl_write_block(global_handle *g, un } - gbl_update_tid (g); - - if (g->locked) { - gbl_unlock (g); - } + gbl_update_tid (g); + gbl_unlock (g); return TRUE; } @@ -578,6 +606,7 @@ global_handle *gbl_handle(char *key) g->use_count = 1; g->locked = FALSE; g->age = time (0L); + g->last_read_time = 0; g->last_block = 0; g->opened = FALSE; g->fd = 0; @@ -586,6 +615,9 @@ global_handle *gbl_handle(char *key) g->cache_hits = 0; g->read_ops = 0; g->write_ops = 0; + g->memory_reads = 0; + g->have_cached_block = FALSE; + g->last_block_accessed = NULL; strcpy (g->global_name, global_name); gbl_path (key, g->global_path); @@ -3716,25 +3748,29 @@ void gbl_dump_stat(void) int hit_pct; unsigned long access_total; unsigned long hit_total; - + unsigned long mem_reads_total; + + mem_reads_total = 0; printf ("\r\nFreeM Global Statistics [PID %d]\r\n\r\n", pid); - printf ("%-20s%-10s%-10s%-10s%-12s%-20s%-10s%s\r\n", "GLOBAL", "USECT", "READS", "WRITES", "SLOW PTHCT", "AGE", "LAST BLK", "FILE"); - printf ("%-20s%-10s%-10s%-10s%-12s%-20s%-10s%s\r\n", "======", "=====", "=====", "======", "==========", "===", "========", "===="); + printf ("%-20s%-10s%-10s%-10s%-10s%-12s%-20s%-10s%s\r\n", "GLOBAL", "USECT", "READS", "WRITES", "MEMREADS", "SLOW PTHCT", "AGE", "LAST BLK", "FILE"); + printf ("%-20s%-10s%-10s%-10s%-10s%-12s%-20s%-10s%s\r\n", "======", "=====", "=====", "======", "========", "==========", "===", "========", "===="); access_total = 0; ct = 0; for (g = global_handles_head; g != NULL; g = g->next) { - printf ("%-20s%-10ld%-10ld%-10ld%-12ld%-20ld%-10ld%s\r\n", + printf ("%-20s%-10ld%-10ld%-10ld%-10ld%-12ld%-20ld%-10ld%s\r\n", g->global_name, g->use_count, g->read_ops, g->write_ops, + g->memory_reads, g->cache_misses, g->age, g->last_block, g->global_path); ct++; + mem_reads_total += g->memory_reads; access_total += g->use_count; } if (!ct) printf ("\r\n"); @@ -3745,5 +3781,7 @@ void gbl_dump_stat(void) printf ("\r\nTotal accesses: %ld\r\n", access_total); printf ("Fast path hits %ld\t(%d%%)\r\n", hit_total, hit_pct); - printf ("Fast path misses: %ld\t(%d%%)\r\n", gbl_cache_misses, miss_pct); + printf ("Fast path misses: %ld\t(%d%%)\r\n", gbl_cache_misses, miss_pct); + printf ("Disk reads avoided: %ld\r\n", mem_reads_total); + }