Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| SHA1 Hash: | 48c63d97899cd20727a8c0fb6292b577b8c87507 |
|---|---|
| Date: | 2009-06-15 19:28:31 |
| User: | stephan |
| Comment: | added compile-time option to disable inode names cache. Disabled by default because the cost is so high for many use cases. TODO: make it runtime-togglable. |
Tags And Properties
- branch=trunk inherited from [d21fde6e87]
- sym-trunk inherited from [d21fde6e87]
Changes
Changes to test.c
| Old (61daa3241291461d) | New (d17fef391a1d7930) | |||
|---|---|---|---|---|
| 1 | /* | 1 | /* | |
| 2 | Test/demo app for libwhefs. | 2 | Test/demo app for libwhefs. | |
| 3 | 3 | |||
| 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | |
| 5 | 5 | |||
| 10 hidden lines | ||||
| 16 | #include <assert.h> | 16 | #include <assert.h> | |
| 17 | #include <unistd.h> /* sleep() */ | 17 | #include <unistd.h> /* sleep() */ | |
| 18 | #include "whefs.h" | 18 | #include "whefs.h" | |
| 19 | #include "whefs_client_util.h" | 19 | #include "whefs_client_util.h" | |
| 20 | 20 | |||
| > | 21 | #include "WHEFSApp.c" | ||
| > | 22 | #if 0 | ||
| 21 | #if 1 | 23 | #if 1 | |
| 22 | #define MARKER if(1) printf("MARKER: %s:%d:%s():\n",__FILE__,__LINE__,__func__); if(1) printf | 24 | #define MARKER if(1) printf("MARKER: %s:%d:%s():\n",__FILE__,__LINE__,__func__); if(1) printf | |
| 23 | #else | 25 | #else | |
| 24 | static void bogo_printf(char const * fmt, ...) {} | 26 | static void bogo_printf(char const * fmt, ...) {} | |
| 25 | #define MARKER if(0) bogo_printf | 27 | #define MARKER if(0) bogo_printf | |
| > | 28 | #endif | ||
| 26 | #endif | 29 | #endif | |
| 27 | 30 | |||
| 28 | 31 | |||
| 29 | struct app_data { | 32 | struct app_data { | |
| 30 | whefs_fs_options fsopts; | 33 | whefs_fs_options fsopts; | |
| 434 hidden lines | ||||
| 465 | 468 | |||
| 466 | extern void whefs_inode_hash_cache_sort(whefs_fs * fs ); | 469 | extern void whefs_inode_hash_cache_sort(whefs_fs * fs ); | |
| 467 | int test_caching() | 470 | int test_caching() | |
| 468 | { | 471 | { | |
| 469 | MARKER("Caching tests...\n"); | 472 | MARKER("Caching tests...\n"); | |
| 470 | const bool toFile = true; /* using a file is many orders of magnitude slower than in-memory (300x on my box at home). */ | | | 473 | const bool toFile = true; /* using a file is many orders of magnitude slower than in-memory (300x on my box at home, but only 10-20x on some very fast drives). */ |
| 471 | whefs_fs * fs = 0; | 474 | whefs_fs * fs = 0; | |
| 472 | char const * const defaultFile = "caching.whefs"; | 475 | char const * const defaultFile = "caching.whefs"; | |
| 473 | char const * fname = toFile | 476 | char const * fname = toFile | |
| 474 | ? defaultFile | 477 | ? defaultFile | |
| 475 | : ":memory:" | 478 | : ":memory:" | |
| 79 hidden lines | ||||
| 555 | whefs_fs_finalize( fs ); | 558 | whefs_fs_finalize( fs ); | |
| 556 | MARKER("End caching tests.\n"); | 559 | MARKER("End caching tests.\n"); | |
| 557 | return 0; | 560 | return 0; | |
| 558 | } | 561 | } | |
| 559 | 562 | |||
| 560 | int main( int argc, char ** argv ) | | | 563 | |
| | | 564 | int main( int argc, char const ** argv ) | ||
| 561 | { | 565 | { | |
| 562 | whefs_setup_debug( stderr, (unsigned int)-1 ); | | | 566 | WHEFSApp.usageText = "[flags]"; |
| | | 567 | WHEFSApp.helpText = | ||
| | | 568 | "Basic test/sanity-check program for whefs." | ||
| | | 569 | ; | ||
| | | 570 | int rc = 0; | ||
| | | 571 | WHEFSApp_init( argc, argv, WHEFSApp_NoOpen, 0, 0 ); // ignore return. | ||
| | | 572 | |||
| | | 573 | //whefs_setup_debug_arg( stderr, "hcl" ); | ||
| 563 | ThisApp.fsopts = whefs_fs_options_default; | 574 | ThisApp.fsopts = whefs_fs_options_default; | |
| 564 | ThisApp.fsopts.inode_count = 16; | 575 | ThisApp.fsopts.inode_count = 16; | |
| 565 | ThisApp.fsopts.block_count = 32; | 576 | ThisApp.fsopts.block_count = 32; | |
| 566 | ThisApp.fsopts.filename_length = 32; | 577 | ThisApp.fsopts.filename_length = 32; | |
| 567 | ThisApp.fsopts.block_size = 1024 * 2; | 578 | ThisApp.fsopts.block_size = 1024 * 2; | |
| 568 | int rc = 0; | | | 579 | if(!rc) rc = test_encodings(); |
| 569 | //if(!rc) rc = test_encodings(); | | | 580 | if(!rc) rc = test_hash(); |
| 570 | //if(!rc) rc = test_hash(); | | | ||
| 571 | if(!rc) rc = test_one(); | 581 | if(!rc) rc = test_one(); | |
| 572 | if(!rc) rc = test_ramfs(); | 582 | if(!rc) rc = test_ramfs(); | |
| 573 | if(!rc) rc = test_multiple_files(); | 583 | if(!rc) rc = test_multiple_files(); | |
| 574 | if(!rc) rc = test_truncate(); | 584 | if(!rc) rc = test_truncate(); | |
| 575 | if(!rc) rc = test_caching(); | 585 | if(!rc) rc = test_caching(); | |
| 577 | (0==rc) | 587 | (0==rc) | |
| 578 | ? "You win :)" | 588 | ? "You win :)" | |
| 579 | : "You lose :("); | 589 | : "You lose :("); | |
| 580 | return rc; | 590 | return rc; | |
| 581 | } | 591 | } | |
Changes to whefs_cache.c
| Old (d2e886ce8d7ef365) | New (f6904bced88a4acf) | |||
|---|---|---|---|---|
| 1 | /** | 1 | /** | |
| 2 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | 2 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | |
| 3 | 3 | |||
| 4 | License: Public Domain | 4 | License: Public Domain | |
| 5 | 5 | |||
| 4 hidden lines | ||||
| 10 | #include <stdlib.h> // free() | 10 | #include <stdlib.h> // free() | |
| 11 | #include <string.h> // memset() | 11 | #include <string.h> // memset() | |
| 12 | #include <assert.h> | 12 | #include <assert.h> | |
| 13 | #include "whefs_cache.h" | 13 | #include "whefs_cache.h" | |
| 14 | 14 | |||
| 15 | const whefs_string_db whefs_string_db_init = whefs_string_db_init_m; | | | 15 | const whefs_string_cache whefs_string_cache_init = whefs_string_cache_init_m; |
| 16 | 16 | |||
| 17 | int whefs_string_db_cleanup( whefs_string_db * db ) | | | 17 | int whefs_string_cache_cleanup( whefs_string_cache * db ) |
| 18 | { | 18 | { | |
| 19 | if( ! db ) return whefs_rc.ArgError; | 19 | if( ! db ) return whefs_rc.ArgError; | |
| 20 | else | 20 | else | |
| 21 | { | 21 | { | |
| 22 | whio_blockdev_cleanup( &db->devBlock ); | 22 | whio_blockdev_cleanup( &db->devBlock ); | |
| 23 | if( db->devMem ) db->devMem->api->finalize( db->devMem ); | 23 | if( db->devMem ) db->devMem->api->finalize( db->devMem ); | |
| 24 | *db = whefs_string_db_init; | | | 24 | *db = whefs_string_cache_init; |
| | | 25 | return whefs_rc.OK; | ||
| | | 26 | } | ||
| | | 27 | |||
| | | 28 | } | ||
| | | 29 | |||
| | | 30 | int whefs_string_cache_clear_contents( whefs_string_cache * db ) | ||
| | | 31 | { | ||
| | | 32 | if( ! db ) return whefs_rc.ArgError; | ||
| | | 33 | else | ||
| | | 34 | { | ||
| | | 35 | if( db->devMem ) db->devMem->api->truncate( db->devMem, 0 ); | ||
| 25 | return whefs_rc.OK; | 36 | return whefs_rc.OK; | |
| 26 | } | 37 | } | |
| 27 | 38 | |||
| 28 | } | 39 | } | |
| 29 | int whefs_string_db_free( whefs_string_db * db ) | | | 40 | |
| | | 41 | int whefs_string_cache_free( whefs_string_cache * db ) | ||
| 30 | { | 42 | { | |
| 31 | const int rc = whefs_string_db_cleanup( db ); | | | 43 | const int rc = whefs_string_cache_cleanup( db ); |
| 32 | if( whefs_rc.OK == rc ) | 44 | if( whefs_rc.OK == rc ) | |
| 33 | { | 45 | { | |
| 34 | free(db); | 46 | free(db); | |
| 35 | } | 47 | } | |
| 36 | return rc; | 48 | return rc; | |
| 37 | } | 49 | } | |
| 38 | 50 | |||
| 39 | int whefs_string_db_setup( whefs_string_db * db, whefs_id_type blockCount, whio_size_t blockSize ) | | | 51 | int whefs_string_cache_setup( whefs_string_cache * db, whefs_id_type blockCount, whio_size_t blockSize ) |
| 40 | { | 52 | { | |
| 41 | if( ! db ) return whefs_rc.ArgError; | 53 | if( ! db ) return whefs_rc.ArgError; | |
| 42 | whefs_string_db_cleanup( db ); | | | 54 | whefs_string_cache_cleanup( db ); |
| 43 | db->devMem = whio_dev_for_membuf( 0, 1.0 ); | 55 | db->devMem = whio_dev_for_membuf( 0, 1.0 ); | |
| > | 56 | static unsigned char wipebuf[WHEFS_MAX_FILENAME_LENGTH+1] = {'*'}; | ||
| > | 57 | if( '*' == wipebuf[0] ) | ||
| > | 58 | { | ||
| > | 59 | memset( wipebuf, 0, WHEFS_MAX_FILENAME_LENGTH+1 ); | ||
| > | 60 | } | ||
| 44 | int rc = whio_blockdev_setup( &db->devBlock, db->devMem, 0U, | 61 | int rc = whio_blockdev_setup( &db->devBlock, db->devMem, 0U, | |
| 45 | blockSize+1/*trailing null!*/, blockCount, 0 ); | | | 62 | blockSize+1/*trailing null!*/, blockCount, wipebuf ); |
| 46 | if( whefs_rc.OK != rc ) | 63 | if( whefs_rc.OK != rc ) | |
| 47 | { | 64 | { | |
| 48 | whefs_string_db_cleanup(db); | | | 65 | whefs_string_cache_cleanup(db); |
| 49 | } | 66 | } | |
| 50 | return rc; | 67 | return rc; | |
| 51 | } | 68 | } | |
| 52 | 69 | |||
| 53 | whefs_string_db * whefs_string_db_create( whefs_id_type blockCount, whio_size_t blockSize ) | | | 70 | whefs_string_cache * whefs_string_cache_create( whefs_id_type blockCount, whio_size_t blockSize ) |
| 54 | { | 71 | { | |
| 55 | whefs_string_db * db = (whefs_string_db*)malloc(sizeof(whefs_string_db)); | | | 72 | whefs_string_cache * db = (whefs_string_cache*)malloc(sizeof(whefs_string_cache)); |
| 56 | if( ! db ) return 0; | 73 | if( ! db ) return 0; | |
| 57 | int rc = whefs_string_db_setup( db, blockCount, blockSize ); | | | 74 | int rc = whefs_string_cache_setup( db, blockCount, blockSize ); |
| 58 | if( whefs_rc.OK != rc ) | 75 | if( whefs_rc.OK != rc ) | |
| 59 | { | 76 | { | |
| 60 | whefs_string_db_free(db); | | | 77 | whefs_string_cache_free(db); |
| 61 | db = 0; | 78 | db = 0; | |
| 62 | } | 79 | } | |
| 63 | return db; | 80 | return db; | |
| 64 | } | 81 | } | |
| 65 | 82 | |||
| 66 | whio_size_t whefs_string_db_memcost( whefs_string_db const * db ) | | | 83 | whio_size_t whefs_string_cache_memcost( whefs_string_cache const * db ) |
| 67 | { | 84 | { | |
| 68 | whio_size_t msize = (whio_size_t)-1; | 85 | whio_size_t msize = (whio_size_t)-1; | |
| 69 | whio_dev_ioctl( db->devMem, whio_dev_ioctl_BUFFER_size, &msize ); | 86 | whio_dev_ioctl( db->devMem, whio_dev_ioctl_BUFFER_size, &msize ); | |
| 70 | if( (whio_size_t)-1 == msize ) | 87 | if( (whio_size_t)-1 == msize ) | |
| 71 | { | 88 | { | |
| 72 | assert( 0 && "whio_dev_ioctl_GENERAL_size not behaving as documented!" ); | 89 | assert( 0 && "whio_dev_ioctl_GENERAL_size not behaving as documented!" ); | |
| 73 | return 0; | 90 | return 0; | |
| 74 | } | 91 | } | |
| 75 | msize += sizeof(whefs_string_db) | | | 92 | msize += sizeof(whefs_string_cache) |
| 76 | + sizeof(*(db->devMem)) | 93 | + sizeof(*(db->devMem)) | |
| 77 | // we don't know the underlying internal costs of db->devMem, other than msize. | 94 | // we don't know the underlying internal costs of db->devMem, other than msize. | |
| 78 | ; | 95 | ; | |
| 79 | return msize; | 96 | return msize; | |
| 80 | } | 97 | } | |
| 81 | int whefs_string_db_set( whefs_string_db * db, whefs_id_type id, char const * str ) | | | 98 | |
| | | 99 | int whefs_string_cache_set( whefs_string_cache * db, whefs_id_type id, char const * str ) | ||
| 82 | { | 100 | { | |
| > | 101 | if(!WHEFS_CONFIG_ENABLE_STRINGS_CACHE) | ||
| > | 102 | { | ||
| > | 103 | return whefs_rc.OK; | ||
| > | 104 | } | ||
| 83 | if( ! whio_blockdev_in_range( db ? &db->devBlock : 0, id ) ) return whefs_rc.ArgError; | 105 | if( ! whio_blockdev_in_range( db ? &db->devBlock : 0, id ) ) return whefs_rc.ArgError; | |
| 84 | size_t slen = (str && *str) ? strlen(str) : 0; | 106 | size_t slen = (str && *str) ? strlen(str) : 0; | |
| 85 | if( db->devBlock.blocks.size <= slen ) return whefs_rc.RangeError; | 107 | if( db->devBlock.blocks.size <= slen ) return whefs_rc.RangeError; | |
| 86 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | 108 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | |
| 87 | unsigned char buf[bufSize]; | | | 109 | unsigned char buf[bufSize] = {0}; |
| | | 110 | #if 1 | ||
| | | 111 | whio_blockdev_wipe( &db->devBlock, id ); | ||
| | | 112 | #endif | ||
| 88 | memcpy( buf, str, slen ); | 113 | memcpy( buf, str, slen ); | |
| 89 | memset( buf + slen, 0, db->devBlock.blocks.size - slen ); | 114 | memset( buf + slen, 0, db->devBlock.blocks.size - slen ); | |
| 90 | //WHEFS_DBG("writing %u bytes for name of inode #%"WHEFS_ID_TYPE_PFMT" as [%s]",slen,id+1,buf); | 115 | //WHEFS_DBG("writing %u bytes for name of inode #%"WHEFS_ID_TYPE_PFMT" as [%s]",slen,id+1,buf); | |
| 91 | const int rc = whio_blockdev_write( &db->devBlock, id, buf ); | 116 | const int rc = whio_blockdev_write( &db->devBlock, id, buf ); | |
| 92 | #if 0 // truncate to a known maximum size if we've allocated above that. | 117 | #if 0 // truncate to a known maximum size if we've allocated above that. | |
| 10 hidden lines | ||||
| 103 | } | 128 | } | |
| 104 | #endif | 129 | #endif | |
| 105 | return rc; | 130 | return rc; | |
| 106 | } | 131 | } | |
| 107 | 132 | |||
| 108 | char const * whefs_string_db_get( whefs_string_db const * db, whefs_id_type id ) | | | 133 | char const * whefs_string_cache_get( whefs_string_cache const * db, whefs_id_type id ) |
| 109 | { | 134 | { | |
| > | 135 | if( ! WHEFS_CONFIG_ENABLE_STRINGS_CACHE ) return 0; | ||
| 110 | #if 0 | 136 | #if 0 | |
| 111 | static char empty[2] = {0,0}; | 137 | static char empty[2] = {0,0}; | |
| 112 | #elseif 0 | 138 | #elseif 0 | |
| 113 | static char const * empty = ""; | 139 | static char const * empty = ""; | |
| 114 | #else | 140 | #else | |
| 115 | static char const * empty = 0; | 141 | static char const * empty = 0; | |
| > | 142 | /** | ||
| > | 143 | Reminder to self: we need to be able to differentiate between | ||
| > | 144 | "found but empty" and "not yet loaded". | ||
| > | 145 | */ | ||
| 116 | #endif | 146 | #endif | |
| 117 | if( ! db ) return 0; | 147 | if( ! db ) return 0; | |
| 118 | if( ! whio_blockdev_in_range( db ? &db->devBlock : 0, id ) ) return 0; | 148 | if( ! whio_blockdev_in_range( db ? &db->devBlock : 0, id ) ) return 0; | |
| 119 | 149 | |||
| 120 | 150 | |||
| 19 hidden lines | ||||
| 140 | { | 170 | { | |
| 141 | mem += off; | 171 | mem += off; | |
| 142 | //WHEFS_DBG("id=%"WHEFS_ID_TYPE_PFMT", mem=%p [%s] [-1=%d]",id,(void const *)mem,(mem?(char const*)mem:"<empty>"), *(mem-1) ); | 172 | //WHEFS_DBG("id=%"WHEFS_ID_TYPE_PFMT", mem=%p [%s] [-1=%d]",id,(void const *)mem,(mem?(char const*)mem:"<empty>"), *(mem-1) ); | |
| 143 | assert( ('\0' == *(mem-1)) && "Logic or memory management error here!"); | 173 | assert( ('\0' == *(mem-1)) && "Logic or memory management error here!"); | |
| 144 | } | 174 | } | |
| 145 | return (char const *)mem; | | | 175 | return (mem && *mem) ? (char const *)mem : (char const *)0; |
| 146 | } | 176 | } | |
| 147 | 177 | |||
| 148 | int whefs_inode_hash_cache_load( whefs_fs * fs ) | 178 | int whefs_inode_hash_cache_load( whefs_fs * fs ) | |
| 149 | { | 179 | { | |
| 150 | #if 1 | 180 | #if 1 | |
| 8 hidden lines | ||||
| 159 | { | 189 | { | |
| 160 | fs->cache.hashes->maxAlloc = fs->options.inode_count; | 190 | fs->cache.hashes->maxAlloc = fs->options.inode_count; | |
| 161 | } | 191 | } | |
| 162 | 192 | |||
| 163 | whefs_hashid_list * li = fs->cache.hashes; | 193 | whefs_hashid_list * li = fs->cache.hashes; | |
| 164 | whefs_hashid h = whefs_hashid_init; | | | 194 | //whefs_hashid h = whefs_hashid_init; |
| 165 | whefs_string name = whefs_string_init; | 195 | whefs_string name = whefs_string_init; | |
| 166 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | 196 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | |
| 167 | unsigned char buf[bufSize]; | 197 | unsigned char buf[bufSize]; | |
| 168 | memset( buf, 0, bufSize ); | 198 | memset( buf, 0, bufSize ); | |
| 169 | // ensure that whefs_inode_name_get() won't malloc(): | 199 | // ensure that whefs_inode_name_get() won't malloc(): | |
| 170 | name.string = (char *)buf; | 200 | name.string = (char *)buf; | |
| 171 | name.alloced = bufSize; | 201 | name.alloced = bufSize; | |
| 172 | int rc = 0; | 202 | int rc = 0; | |
| 173 | whefs_id_type i; | 203 | whefs_id_type i; | |
| 174 | size_t count = 0; | | | 204 | //size_t count = 0; |
| 175 | for( i = fs->options.inode_count; i >=1 ; --i ) | 205 | for( i = fs->options.inode_count; i >=1 ; --i ) | |
| 176 | { | 206 | { | |
| 177 | /** | 207 | /** | |
| 178 | Maintenance reminder: | 208 | Maintenance reminder: | |
| 179 | 209 | |||
| 180 | We do this loop in reverse order as an efficiency hack for | 210 | We do this loop in reverse order as an efficiency hack for | |
| 181 | whefs_string_db. The trick is: the whefs_string_db's | | | 211 | whefs_string_cache. The trick is: the whefs_string_cache's |
| 182 | internal buffer grows only as the number of used inodes | 212 | internal buffer grows only as the number of used inodes | |
| 183 | does (it's size is a function of the highest used inode | 213 | does (it's size is a function of the highest used inode | |
| 184 | ID). If we insert from low to high it may realloc many | 214 | ID). If we insert from low to high it may realloc many | |
| 185 | times. If we insert from high to low, we're guaranteed to | 215 | times. If we insert from high to low, we're guaranteed to | |
| 186 | need only one malloc/realloc on it. | 216 | need only one malloc/realloc on it. | |
| 7 hidden lines | ||||
| 194 | } | 224 | } | |
| 195 | } | 225 | } | |
| 196 | #endif // WHEFS_FS_BITSET_CACHE_ENABLED | 226 | #endif // WHEFS_FS_BITSET_CACHE_ENABLED | |
| 197 | rc = whefs_inode_name_get( fs, i, &name ); | 227 | rc = whefs_inode_name_get( fs, i, &name ); | |
| 198 | if( whefs_rc.OK != rc ) break; | 228 | if( whefs_rc.OK != rc ) break; | |
| > | 229 | #if 0 | ||
| > | 230 | // already done via whefs_inode_name_get(). | ||
| 199 | if( !*name.string ) continue; | 231 | if( !*name.string ) continue; | |
| 200 | ++count; | 232 | ++count; | |
| 201 | h.id = i; | 233 | h.id = i; | |
| 202 | h.hash = fs->cache.hashfunc( name.string ); | 234 | h.hash = fs->cache.hashfunc( name.string ); | |
| 203 | whefs_hashid_list_add( li, &h ); | 235 | whefs_hashid_list_add( li, &h ); | |
| > | 236 | #endif | ||
| 204 | } | 237 | } | |
| 205 | assert( (name.string == (char *)buf) && "Internal memory management foo-foo." ); | 238 | assert( (name.string == (char *)buf) && "Internal memory management foo-foo." ); | |
| 206 | whefs_hashid_list_sort(li); | 239 | whefs_hashid_list_sort(li); | |
| 207 | //WHEFS_DBG("loaded names caches with %u name(s).",count); | 240 | //WHEFS_DBG("loaded names caches with %u name(s).",count); | |
| 208 | return rc; | 241 | return rc; | |
| 69 hidden lines | ||||
| 278 | { | 311 | { | |
| 279 | #if DISABLE_NAME_CACHE | 312 | #if DISABLE_NAME_CACHE | |
| 280 | return whefs_rc.OK; | 313 | return whefs_rc.OK; | |
| 281 | #endif | 314 | #endif | |
| 282 | if( ! fs || !name || !*name ) return whefs_rc.ArgError; | 315 | if( ! fs || !name || !*name ) return whefs_rc.ArgError; | |
| 283 | int rc = whefs_string_db_set( &fs->cache.strings, id-1, name ); | | | 316 | int rc = whefs_string_cache_set( &fs->cache.strings, id-1, name ); |
| 284 | if( whefs_rc.OK != rc ) return rc; | 317 | if( whefs_rc.OK != rc ) return rc; | |
| 285 | if( ! fs->cache.hashes ) | 318 | if( ! fs->cache.hashes ) | |
| 286 | { | 319 | { | |
| 287 | const whefs_id_type max = fs->options.inode_count; | 320 | const whefs_id_type max = fs->options.inode_count; | |
| 288 | whefs_id_type dflt = 100/sizeof(whefs_hashid) /*for lack of a better default value.*/; | 321 | whefs_id_type dflt = 100/sizeof(whefs_hashid) /*for lack of a better default value.*/; | |
| 29 hidden lines | ||||
| 318 | H.id = id; | 351 | H.id = id; | |
| 319 | rc = whefs_hashid_list_add( fs->cache.hashes, &H ); | 352 | rc = whefs_hashid_list_add( fs->cache.hashes, &H ); | |
| 320 | if(0) WHEFS_DBG("Added to name cache: hash[%"WHEFS_HASHVAL_TYPE_PFMT"]=id[%"WHEFS_ID_TYPE_PFMT"], name=[%s], rc=%d", H.hash, H.id, name, rc ); | 353 | if(0) WHEFS_DBG("Added to name cache: hash[%"WHEFS_HASHVAL_TYPE_PFMT"]=id[%"WHEFS_ID_TYPE_PFMT"], name=[%s], rc=%d", H.hash, H.id, name, rc ); | |
| 321 | return whefs_rc.OK; | 354 | return whefs_rc.OK; | |
| 322 | } | 355 | } | |
Changes to whefs_cache.h
| Old (36c19eae72cfe99c) | New (80626a8fe4189b1e) | |||
|---|---|---|---|---|
| 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED) | 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED) | |
| 2 | #define WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED 1 | 2 | #define WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED 1 | |
| 3 | /* | 3 | /* | |
| 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | |
| 5 | 5 | |||
| 17 hidden lines | ||||
| 23 | An internal type for caching strings via a whio_dev memory | 23 | An internal type for caching strings via a whio_dev memory | |
| 24 | device. This optimizes the storage by using a contiguous | 24 | device. This optimizes the storage by using a contiguous | |
| 25 | array for all strings. Unfortunately, each entry in the cache | 25 | array for all strings. Unfortunately, each entry in the cache | |
| 26 | must have a set length, however. | 26 | must have a set length, however. | |
| 27 | */ | 27 | */ | |
| 28 | struct whefs_string_db | | | 28 | struct whefs_string_cache |
| 29 | { | 29 | { | |
| 30 | /** | 30 | /** | |
| 31 | Block device manager for writing strings. | 31 | Block device manager for writing strings. | |
| 32 | */ | 32 | */ | |
| 33 | whio_blockdev devBlock; | 33 | whio_blockdev devBlock; | |
| 4 hidden lines | ||||
| 38 | /** | 38 | /** | |
| 39 | Internal buffer used for encoding/decoding. | 39 | Internal buffer used for encoding/decoding. | |
| 40 | */ | 40 | */ | |
| 41 | //unsigned char buf[WHEFS_MAX_FILENAME_LENGTH+1]; | 41 | //unsigned char buf[WHEFS_MAX_FILENAME_LENGTH+1]; | |
| 42 | }; | 42 | }; | |
| 43 | typedef struct whefs_string_db whefs_string_db; | | | 43 | typedef struct whefs_string_cache whefs_string_cache; |
| 44 | /** Empty initialization whefs_string_db object. */ | | | 44 | /** Empty initialization whefs_string_cache object. */ |
| 45 | #define whefs_string_db_init_m { \ | | | 45 | #define whefs_string_cache_init_m { \ |
| 46 | whio_blockdev_init_m/*devBlock*/, \ | 46 | whio_blockdev_init_m/*devBlock*/, \ | |
| 47 | 0/*devMem*/ \ | 47 | 0/*devMem*/ \ | |
| 48 | } | 48 | } | |
| 49 | 49 | |||
| 50 | /** Empty initialization whefs_string_db object. */ | | | 50 | /** Empty initialization whefs_string_cache object. */ |
| 51 | extern const whefs_string_db whefs_string_db_init; | | | 51 | extern const whefs_string_cache whefs_string_cache_init; |
| 52 | /** | 52 | /** | |
| 53 | Calls whefs_string_db_cleanup() then frees db. | | | 53 | Calls whefs_string_cache_cleanup() then frees db. |
| 54 | */ | 54 | */ | |
| 55 | int whefs_string_db_free( whefs_string_db * db ); | | | 55 | int whefs_string_cache_free( whefs_string_cache * db ); |
| 56 | /** | 56 | /** | |
| 57 | Deallocates all resources associated with db, but does not free db | 57 | Deallocates all resources associated with db, but does not free db | |
| 58 | itself. It can be re-used in another call to | 58 | itself. It can be re-used in another call to | |
| 59 | whefs_string_db_setup() or freed using whefs_string_db_free(). | | | 59 | whefs_string_cache_setup() or freed using whefs_string_cache_free(). |
| | | 60 | */ | ||
| | | 61 | int whefs_string_cache_cleanup( whefs_string_cache * db ); | ||
| | | 62 | |||
| | | 63 | /** | ||
| | | 64 | Truncates the internal string table of db to 0 bytes, potentially freeing | ||
| | | 65 | up memory. db is still a valid/usable object after calling this. | ||
| 60 | */ | 66 | */ | |
| 61 | int whefs_string_db_cleanup( whefs_string_db * db ); | | | 67 | int whefs_string_cache_clear_contents( whefs_string_cache * db ); |
| | | 68 | |||
| 62 | /** | 69 | /** | |
| 63 | Sets up db, which must be initialized memory (use | 70 | Sets up db, which must be initialized memory (use | |
| 64 | whefs_string_db_init or whefs_string_db_init_m to initialize it). | | | 71 | whefs_string_cache_init or whefs_string_cache_init_m to initialize it). |
| 65 | db will be able to hold a number (blockCount) of fixed-size blocks of | 72 | db will be able to hold a number (blockCount) of fixed-size blocks of | |
| 66 | blockSize bytes each. | 73 | blockSize bytes each. | |
| 67 | 74 | |||
| 68 | On success whefs_rc.OK is returned. | 75 | On success whefs_rc.OK is returned. | |
| 69 | */ | 76 | */ | |
| 70 | int whefs_string_db_setup( whefs_string_db * db, whefs_id_type blockCount, whio_size_t blockSize ); | | | 77 | int whefs_string_cache_setup( whefs_string_cache * db, whefs_id_type blockCount, whio_size_t blockSize ); |
| 71 | 78 | |||
| 72 | /** | 79 | /** | |
| 73 | Creates a new whefs_string_db with the given capacity. On error | | | 80 | Creates a new whefs_string_cache with the given capacity. On error |
| 74 | returns 0, else a new object which must be eventually deleted by | 81 | returns 0, else a new object which must be eventually deleted by | |
| 75 | passing it to whefs_string_db_free(). | | | 82 | passing it to whefs_string_cache_free(). |
| 76 | */ | 83 | */ | |
| 77 | whefs_string_db * whefs_string_db_create( whefs_id_type blockCount, whio_size_t blockSize ); | | | 84 | whefs_string_cache * whefs_string_cache_create( whefs_id_type blockCount, whio_size_t blockSize ); |
| 78 | /** | 85 | /** | |
| 79 | Sets the given record to the given str value. str may be null or empty but | 86 | Sets the given record to the given str value. str may be null or empty but | |
| 80 | may not be longer than db's block size. It is copied, and need not live | 87 | may not be longer than db's block size. It is copied, and need not live | |
| 81 | longer than this call. | 88 | longer than this call. | |
| 82 | 89 | |||
| 83 | Error cases: | 90 | Error cases: | |
| 84 | 91 | |||
| 85 | whefs_rc.ArgError = !db or id is out of range for db. | 92 | whefs_rc.ArgError = !db or id is out of range for db. | |
| 86 | 93 | |||
| 87 | whefs_rc.RangeError = str is longer than db's block size, as passed | 94 | whefs_rc.RangeError = str is longer than db's block size, as passed | |
| 88 | to whefs_string_db_create() or whefs_string_db_setup(). | | | 95 | to whefs_string_cache_create() or whefs_string_cache_setup(). |
| 89 | 96 | |||
| 90 | whio_rc.AllocError = underying cache memory could not be allocated. | 97 | whio_rc.AllocError = underying cache memory could not be allocated. | |
| 91 | 98 | |||
| 92 | In theory, another whio_rc error may be propagated, but i can't | 99 | In theory, another whio_rc error may be propagated, but i can't | |
| 93 | think of a reason why it would other than an internal bug. | 100 | think of a reason why it would other than an internal bug. | |
| 95 | This is an O(N) operation, where N is the length of db's blocks, but it involves | 102 | This is an O(N) operation, where N is the length of db's blocks, but it involves | |
| 96 | only simple math, memcpy() and memset(), so it's pretty past. If | 103 | only simple math, memcpy() and memset(), so it's pretty past. If | |
| 97 | the underlying cache must reallocate to grow then it also takes on | 104 | the underlying cache must reallocate to grow then it also takes on | |
| 98 | the performance characteristics of realloc(). | 105 | the performance characteristics of realloc(). | |
| 99 | 106 | |||
| 100 | @see whefs_string_db_get() | | | 107 | @see whefs_string_cache_get() |
| 101 | */ | 108 | */ | |
| 102 | int whefs_string_db_set( whefs_string_db * db, whefs_id_type id, char const * str ); | | | 109 | int whefs_string_cache_set( whefs_string_cache * db, whefs_id_type id, char const * str ); |
| 103 | 110 | |||
| 104 | /** | 111 | /** | |
| 105 | Gets the string at the given block number. | 112 | Gets the string at the given block number. | |
| 106 | 113 | |||
| 107 | On success (i.e. a cache entry was found) it returns a pointer to | 114 | On success (i.e. a cache entry was found) it returns a pointer to | |
| 108 | the cached string bytes (null-terminated). They are owned by db and | 115 | the cached string bytes (null-terminated). They are owned by db and | |
| 109 | may be reallocated or destroyed by any whefs_string_db_set() calls, | | | 116 | may be reallocated or destroyed by any whefs_string_cache_set() calls, |
| 110 | so they should be copied if they are to be held long-term. | 117 | so they should be copied if they are to be held long-term. | |
| 111 | 118 | |||
| 112 | This is an O(1) operation. | 119 | This is an O(1) operation. | |
| 113 | 120 | |||
| 114 | This function returns 0 (NULL) if the name cannot be read (i.e. it | 121 | This function returns 0 (NULL) if the name cannot be read (i.e. it | |
| 115 | has not be cached yet, or caching has been disabled), if the id is | 122 | has not be cached yet, or caching has been disabled), if the id is | |
| 116 | out of bounds, or a few other theoretical but not likely cases. | 123 | out of bounds, or a few other theoretical but not likely cases. | |
| 117 | 124 | |||
| 118 | @see whefs_string_db_set(). | | | 125 | @see whefs_string_cache_set(). |
| 119 | */ | 126 | */ | |
| 120 | char const * whefs_string_db_get( whefs_string_db const * db, whefs_id_type id ); | | | 127 | char const * whefs_string_cache_get( whefs_string_cache const * db, whefs_id_type id ); |
| 121 | /** | 128 | /** | |
| 122 | Returns an approximate cost of the memory associated with db, which | 129 | Returns an approximate cost of the memory associated with db, which | |
| 123 | must be a fully-setup object. The real cost is slightly higher than | 130 | must be a fully-setup object. The real cost is slightly higher than | |
| 124 | the returned value, as there are internal details which this code | 131 | the returned value, as there are internal details which this code | |
| 125 | does not have access to, so it cannot measure them. | 132 | does not have access to, so it cannot measure them. | |
| 126 | */ | 133 | */ | |
| 127 | whio_size_t whefs_string_db_memcost( whefs_string_db const * db ); | | | 134 | whio_size_t whefs_string_cache_memcost( whefs_string_cache const * db ); |
| 128 | 135 | |||
| 129 | #ifdef __cplusplus | 136 | #ifdef __cplusplus | |
| 130 | } /* extern "C" */ | 137 | } /* extern "C" */ | |
| 131 | #endif | 138 | #endif | |
| 132 | 139 | |||
| 133 | 140 | |||
| 134 | #endif /* WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED */ | 141 | #endif /* WANDERINGHORSE_NET_WHEFS_CACHE_H_INCLUDED */ | |
Changes to whefs_config.h
| Old (42c26bf40dc62fb8) | New (99dc3053631fc38e) | |||
|---|---|---|---|---|
| 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED) | 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED) | |
| 2 | #define WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED | 2 | #define WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED | |
| 3 | 3 | |||
| 4 | /* | 4 | /* | |
| 5 | This file contains the compile-time-configurable parts of | 5 | This file contains the compile-time-configurable parts of | |
| 289 hidden lines | ||||
| 295 | #if !defined(DOXYGEN) | 295 | #if !defined(DOXYGEN) | |
| 296 | # define WHEFS_MACROIZE_SMALL_CHECKS 0 | 296 | # define WHEFS_MACROIZE_SMALL_CHECKS 0 | |
| 297 | #else | 297 | #else | |
| 298 | # define WHEFS_MACROIZE_SMALL_CHECKS 0 | 298 | # define WHEFS_MACROIZE_SMALL_CHECKS 0 | |
| 299 | #endif | 299 | #endif | |
| > | 300 | |||
| > | 301 | /** | ||
| > | 302 | If WHEFS_CONFIG_ENABLE_STRINGS_CACHE is 0 then the internal inode | ||
| > | 303 | name string caching mechanism is disabled. The cache costs a | ||
| > | 304 | significant amount of memory (proportional to the number of used | ||
| > | 305 | inodes multiplied by the maximum filename length), but can save i/o | ||
| > | 306 | when files are searched by name often or their names are fetched | ||
| > | 307 | more than once. Any performance gains are only noted in apps which | ||
| > | 308 | have an unusually high amount of lookups by name. When it is turned | ||
| > | 309 | on, the whole inode names table is read and the cache is | ||
| > | 310 | populated. If the client searches by name less times than there are | ||
| > | 311 | used inodes, the loading of the cache costs more than any relative | ||
| > | 312 | benefit. Thus it is disabled by default. | ||
| > | 313 | |||
| > | 314 | In fact, an app may (and is likely to) end up making more calls to | ||
| > | 315 | malloc() and free() with the cache turned off, but they are likely | ||
| > | 316 | to not hold as much memory open at one time compared to the cache. | ||
| > | 317 | |||
| > | 318 | FIXME: make this runtime-togglable. | ||
| > | 319 | */ | ||
| > | 320 | #define WHEFS_CONFIG_ENABLE_STRINGS_CACHE 0 | ||
| 300 | 321 | |||
| 301 | #ifdef __cplusplus | 322 | #ifdef __cplusplus | |
| 302 | } /* extern "C" */ | 323 | } /* extern "C" */ | |
| 303 | #endif | 324 | #endif | |
| 304 | 325 | |||
| 305 | 326 | |||
| 306 | #endif /* WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED */ | 327 | #endif /* WANDERINGHORSE_NET_WHEFS_CONFIG_H_INCLUDED */ | |
Changes to whefs_details.c
| Old (8bde80f305ca6936) | New (07b8a5d618bcbcae) | |||
|---|---|---|---|---|
| 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED) | 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED) | |
| 2 | #define WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED 1 | 2 | #define WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED 1 | |
| 3 | #if ! defined __STDC_FORMAT_MACROS | 3 | #if ! defined __STDC_FORMAT_MACROS | |
| 4 | # define __STDC_FORMAT_MACROS 1 | 4 | # define __STDC_FORMAT_MACROS 1 | |
| 5 | #endif | 5 | #endif | |
| 267 hidden lines | ||||
| 273 | } threads; | 273 | } threads; | |
| 274 | struct _caches | 274 | struct _caches | |
| 275 | { | 275 | { | |
| 276 | whefs_hashid_list * hashes; | 276 | whefs_hashid_list * hashes; | |
| 277 | whefs_hashval_type (*hashfunc)( char const * vstr); | 277 | whefs_hashval_type (*hashfunc)( char const * vstr); | |
| 278 | whefs_string_db strings; | | | 278 | whefs_string_cache strings; |
| 279 | } cache; | 279 | } cache; | |
| 280 | }; | 280 | }; | |
| 281 | 281 | |||
| 282 | /** Empty initialization object. */ | 282 | /** Empty initialization object. */ | |
| 283 | extern const whefs_fs whefs_fs_init; | 283 | extern const whefs_fs whefs_fs_init; | |
| 479 hidden lines | ||||
| 763 | void whefs_inode_hash_cache_sort(whefs_fs * fs ); | 763 | void whefs_inode_hash_cache_sort(whefs_fs * fs ); | |
| 764 | 764 | |||
| 765 | int whefs_fs_cache_name( whefs_fs * fs, whefs_id_type id, char const * n ); | 765 | int whefs_fs_cache_name( whefs_fs * fs, whefs_id_type id, char const * n ); | |
| 766 | 766 | |||
| 767 | #endif /* WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED */ | 767 | #endif /* WANDERINGHORSE_NET_WHEFS_DETAILS_C_INCLUDED */ | |
Changes to whefs_fs.c
| Old (82b4dbaece4de700) | New (fc5d5b096ea49ee9) | |||
|---|---|---|---|---|
| 1 | /* | 1 | /* | |
| 2 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | 2 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | |
| 3 | 3 | |||
| 4 | License: Public Domain | 4 | License: Public Domain | |
| 5 | 5 | |||
| 19 hidden lines | ||||
| 25 | #endif | 25 | #endif | |
| 26 | 26 | |||
| 27 | #define WHEFS_LOAD_CACHES_ON_OPEN 1 /* make sure and test whefs-cp and friends if setting this to 0. */ | 27 | #define WHEFS_LOAD_CACHES_ON_OPEN 1 /* make sure and test whefs-cp and friends if setting this to 0. */ | |
| 28 | #if ! WHEFS_LOAD_CACHES_ON_OPEN | 28 | #if ! WHEFS_LOAD_CACHES_ON_OPEN | |
| 29 | # warning "(0==WHEFS_LOAD_CACHES_ON_OPEN) is is known to cause bugs. Fix it!" | 29 | # warning "(0==WHEFS_LOAD_CACHES_ON_OPEN) is is known to cause bugs. Fix it!" | |
| > | 30 | /* | ||
| > | 31 | Reminder to self: the problem here is one of "how do we distinguish empty names vs. not-cached names," | ||
| > | 32 | and is complicated by the voodoo we use to store the strings inside whefs_fs::cache::strings. | ||
| > | 33 | */ | ||
| 30 | #endif | 34 | #endif | |
| > | 35 | |||
| 31 | #if WHIO_ENABLE_THREADS | 36 | #if WHIO_ENABLE_THREADS | |
| 32 | /** | 37 | /** | |
| 33 | WHEFS_FS_STRUCT_THREAD_INFO is the initializer for whefs_fs.threads. | 38 | WHEFS_FS_STRUCT_THREAD_INFO is the initializer for whefs_fs.threads. | |
| 34 | */ | 39 | */ | |
| 35 | # define WHEFS_FS_STRUCT_THREAD_INFO {/*threads*/ \ | 40 | # define WHEFS_FS_STRUCT_THREAD_INFO {/*threads*/ \ | |
| 7 hidden lines | ||||
| 43 | /* whefs_fs::cache struct ... */ | 48 | /* whefs_fs::cache struct ... */ | |
| 44 | #define WHEFS_FS_STRUCT_CACHE \ | 49 | #define WHEFS_FS_STRUCT_CACHE \ | |
| 45 | {/*cache*/ \ | 50 | {/*cache*/ \ | |
| 46 | 0/*hashes*/, \ | 51 | 0/*hashes*/, \ | |
| 47 | whefs_hash_cstring/*hashfunc*/, \ | 52 | whefs_hash_cstring/*hashfunc*/, \ | |
| 48 | whefs_string_db_init_m/*strings*/ \ | | | 53 | whefs_string_cache_init_m/*strings*/ \ |
| 49 | } | 54 | } | |
| 50 | /* whefs_fs::fences struct ... */ | 55 | /* whefs_fs::fences struct ... */ | |
| 51 | #define WHEFS_FS_STRUCT_FENCES \ | 56 | #define WHEFS_FS_STRUCT_FENCES \ | |
| 52 | { /* fences */ \ | 57 | { /* fences */ \ | |
| 53 | whio_blockdev_init_m /* s */, \ | 58 | whio_blockdev_init_m /* s */, \ | |
| 228 hidden lines | ||||
| 282 | whefs_hashid_list_alloc( &fs->cache.hashes, 0 );// reminder: we keep fs->cache.hashes itself until finalization. | 287 | whefs_hashid_list_alloc( &fs->cache.hashes, 0 );// reminder: we keep fs->cache.hashes itself until finalization. | |
| 283 | } | 288 | } | |
| 284 | if(1) | 289 | if(1) | |
| 285 | { | 290 | { | |
| 286 | WHEFS_DBG_CACHE("Emptying names string cache using approximately %"WHIO_SIZE_T_PFMT" bytes.", | 291 | WHEFS_DBG_CACHE("Emptying names string cache using approximately %"WHIO_SIZE_T_PFMT" bytes.", | |
| 287 | whefs_string_db_memcost( &fs->cache.strings ) ); | | | 292 | whefs_string_cache_memcost( &fs->cache.strings ) ); |
| | | 293 | whefs_string_cache_clear_contents( &fs->cache.strings ); | ||
| 288 | } | 294 | } | |
| 289 | } | 295 | } | |
| 290 | void whefs_fs_caches_clear( whefs_fs * restrict fs ) | 296 | void whefs_fs_caches_clear( whefs_fs * restrict fs ) | |
| 291 | { | 297 | { | |
| 292 | whbits_free_bits( &fs->bits.i ); | 298 | whbits_free_bits( &fs->bits.i ); | |
| 20 hidden lines | ||||
| 313 | whefs_fs_caches_clear(fs); | 319 | whefs_fs_caches_clear(fs); | |
| 314 | whefs_hashid_list_free( fs->cache.hashes ); | 320 | whefs_hashid_list_free( fs->cache.hashes ); | |
| 315 | whio_blockdev_cleanup ( &fs->fences.s ); | 321 | whio_blockdev_cleanup ( &fs->fences.s ); | |
| 316 | whio_blockdev_cleanup ( &fs->fences.i ); | 322 | whio_blockdev_cleanup ( &fs->fences.i ); | |
| 317 | //whio_blockdev_cleanup ( &fs->fences.b ); | 323 | //whio_blockdev_cleanup ( &fs->fences.b ); | |
| 318 | whefs_string_db_cleanup( &fs->cache.strings ); | | | 324 | whefs_string_cache_cleanup( &fs->cache.strings ); |
| 319 | if( fs->dev ) | 325 | if( fs->dev ) | |
| 320 | { | 326 | { | |
| 321 | whefs_fs_flush(fs); | 327 | whefs_fs_flush(fs); | |
| 322 | whefs_fs_unlock( fs, 0, SEEK_SET, 0 ); | 328 | whefs_fs_unlock( fs, 0, SEEK_SET, 0 ); | |
| 323 | if( fs->ownsDev ) fs->dev->api->finalize( fs->dev ); | 329 | if( fs->ownsDev ) fs->dev->api->finalize( fs->dev ); | |
| 168 hidden lines | ||||
| 492 | } | 498 | } | |
| 493 | 499 | |||
| 494 | int whefs_inode_name_get( whefs_fs * restrict fs, whefs_id_type id, whefs_string * tgt ) | 500 | int whefs_inode_name_get( whefs_fs * restrict fs, whefs_id_type id, whefs_string * tgt ) | |
| 495 | { | 501 | { | |
| 496 | if( ! tgt || ! whefs_inode_id_is_valid( fs, id ) ) return whefs_rc.ArgError; | 502 | if( ! tgt || ! whefs_inode_id_is_valid( fs, id ) ) return whefs_rc.ArgError; | |
| 497 | if(1) do | | | 503 | if( WHEFS_CONFIG_ENABLE_STRINGS_CACHE ) |
| 498 | { | 504 | { | |
| 499 | static uint32_t hitmiss[2] = {0,0}; | 505 | static uint32_t hitmiss[2] = {0,0}; | |
| 500 | char const * cached = whefs_string_db_get( &fs->cache.strings, id-1 ); | | | 506 | char const * cached = whefs_string_cache_get( &fs->cache.strings, id-1 ); |
| 501 | if( cached && *cached ) | 507 | if( cached && *cached ) | |
| 502 | { | 508 | { | |
| 503 | /* reminder: *cached is ambiguous: it could be an unused inode slot or | | | 509 | /* reminder: (!*cached) is ambiguous: it could be an unused inode slot or |
| 504 | an empty name. | 510 | an empty name. | |
| 505 | */ | 511 | */ | |
| 506 | //WHEFS_DBG("Got cached name for inode #%"WHEFS_ID_TYPE_PFMT" [%s]",id,cached); | 512 | //WHEFS_DBG("Got cached name for inode #%"WHEFS_ID_TYPE_PFMT" [%s]",id,cached); | |
| 507 | //WHEFS_DBG("[inode strings db: misses=%u Hits=%u][name=[%s]]",hitmiss[0],hitmiss[1],cached); | 513 | //WHEFS_DBG("[inode strings db: misses=%u Hits=%u][name=[%s]]",hitmiss[0],hitmiss[1],cached); | |
| 508 | ++hitmiss[1]; | 514 | ++hitmiss[1]; | |
| 509 | return whefs_string_copy_cstring( tgt, cached ); | 515 | return whefs_string_copy_cstring( tgt, cached ); | |
| 510 | } | 516 | } | |
| 511 | ++hitmiss[0]; | 517 | ++hitmiss[0]; | |
| 512 | } | 518 | } | |
| 513 | while(false); | < | ||
| 514 | 519 | |||
| 515 | // FIXME: check opened inodes first! | | | 520 | // FIXME? check opened inodes first? |
| 516 | int rc = 0; | 521 | int rc = 0; | |
| 517 | unsigned char buf[whefs_sizeof_encoded_inode_name]; | 522 | unsigned char buf[whefs_sizeof_encoded_inode_name]; | |
| 518 | memset( buf, 0, whefs_sizeof_encoded_inode_name ); | 523 | memset( buf, 0, whefs_sizeof_encoded_inode_name ); | |
| 519 | assert( (fs->fences.s.blocks.size == fs->sizes[WHEFS_SZ_INODE_NAME]) && "fs inode name size has not been set up properly!" ); | 524 | assert( (fs->fences.s.blocks.size == fs->sizes[WHEFS_SZ_INODE_NAME]) && "fs inode name size has not been set up properly!" ); | |
| 520 | assert(fs->sizes[WHEFS_SZ_INODE_NAME] && "fs has not been set up properly!"); | 525 | assert(fs->sizes[WHEFS_SZ_INODE_NAME] && "fs has not been set up properly!"); | |
| 463 hidden lines | ||||
| 984 | fs->sizes[WHEFS_SZ_BLOCK], | 989 | fs->sizes[WHEFS_SZ_BLOCK], | |
| 985 | fs->options.block_count, | 990 | fs->options.block_count, | |
| 986 | 0 /* FIXME: we need a prototype, but need the encoding routines for that first. */ ); | 991 | 0 /* FIXME: we need a prototype, but need the encoding routines for that first. */ ); | |
| 987 | #endif | 992 | #endif | |
| 988 | 993 | |||
| 989 | rc = whefs_string_db_setup( &fs->cache.strings, fs->options.inode_count, fs->options.filename_length ); | | | 994 | rc = whefs_string_cache_setup( &fs->cache.strings, fs->options.inode_count, fs->options.filename_length ); |
| 990 | 995 | |||
| 991 | return rc; | 996 | return rc; | |
| 992 | } | 997 | } | |
| 993 | 998 | |||
| 994 | 999 | |||
| 366 hidden lines | ||||
| 1361 | X(whio_stream), | 1366 | X(whio_stream), | |
| 1362 | X(whio_stream_api), | 1367 | X(whio_stream_api), | |
| 1363 | #endif | 1368 | #endif | |
| 1364 | X(whbits), | 1369 | X(whbits), | |
| 1365 | X(whefs_string), | 1370 | X(whefs_string), | |
| 1366 | X(whefs_string_db), | | | 1371 | X(whefs_string_cache), |
| 1367 | X(whefs_inode), | 1372 | X(whefs_inode), | |
| 1368 | X(whefs_block), | 1373 | X(whefs_block), | |
| 1369 | X(whefs_hashid), | 1374 | X(whefs_hashid), | |
| 1370 | X(whefs_hashid_list), | 1375 | X(whefs_hashid_list), | |
| 1371 | {0,0} | 1376 | {0,0} | |
| 85 hidden lines | ||||
| 1457 | if( whefs_rc.OK != rc ) break; | 1462 | if( whefs_rc.OK != rc ) break; | |
| 1458 | } | 1463 | } | |
| 1459 | whefs_fs_flush( fs ); | 1464 | whefs_fs_flush( fs ); | |
| 1460 | return rc; | 1465 | return rc; | |
| 1461 | } | 1466 | } | |
Changes to whefs_inode.c
| Old (3cb755439006314b) | New (ff3760ef7b8e4b23) | |||
|---|---|---|---|---|
| 1 | /* | 1 | /* | |
| 2 | Implementations for whefs_inode operations. | 2 | Implementations for whefs_inode operations. | |
| 3 | 3 | |||
| 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) | |
| 5 | 5 | |||
| 96 hidden lines | ||||
| 102 | fs->hints.unused_inode_start = ino->id; | 102 | fs->hints.unused_inode_start = ino->id; | |
| 103 | } | 103 | } | |
| 104 | } | 104 | } | |
| 105 | } | 105 | } | |
| 106 | 106 | |||
| > | 107 | |||
| 107 | int whefs_inode_name_set( whefs_fs * fs, whefs_id_type nid, char const * name ) | 108 | int whefs_inode_name_set( whefs_fs * fs, whefs_id_type nid, char const * name ) | |
| 108 | { | 109 | { | |
| 109 | //if( !n || !n->id ) return whefs_rc.ArgError; | 110 | //if( !n || !n->id ) return whefs_rc.ArgError; | |
| 110 | if( !whefs_inode_id_is_valid(fs,nid) ) | 111 | if( !whefs_inode_id_is_valid(fs,nid) ) | |
| 111 | { | 112 | { | |
| 112 | return whefs_rc.ArgError; | 113 | return whefs_rc.ArgError; | |
| 113 | } | 114 | } | |
| 114 | int rc = 0; | 115 | int rc = 0; | |
| > | 116 | |||
| > | 117 | /** | ||
| > | 118 | We have to see if we have an existing entry for the given inode ID, so | ||
| > | 119 | we can replace its hashvalue in the cache. If we don't do this we end | ||
| > | 120 | up with stale/useless entries in the cache. | ||
| > | 121 | */ | ||
| 115 | whefs_inode * nop = 0; | 122 | whefs_inode * nop = 0; | |
| 116 | whefs_hashid * H = 0; | 123 | whefs_hashid * H = 0; | |
| 117 | char const * oldName; oldName = whefs_string_db_get( &fs->cache.strings, nid-1 ); | | | 124 | char const * nameCheck = name; |
| | | 125 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH + 1 }; | ||
| | | 126 | char buf[bufSize] = {0}; | ||
| | | 127 | whefs_string ncheck = whefs_string_init; | ||
| | | 128 | ncheck.string = buf; | ||
| | | 129 | ncheck.alloced = bufSize; | ||
| | | 130 | if(1) | ||
| | | 131 | { | ||
| | | 132 | rc = whefs_inode_name_get( fs, nid, &ncheck ); | ||
| | | 133 | assert( (ncheck.string == buf) && "illegal (re)alloc!"); | ||
| | | 134 | if( whefs_rc.OK != rc ) return rc; | ||
| | | 135 | if( *buf && (0==strcmp(buf,name))) return whefs_rc.OK; | ||
| | | 136 | if( *buf ) nameCheck = ncheck.string; | ||
| | | 137 | } | ||
| 118 | #if 1 | 138 | #if 1 | |
| 119 | whefs_id_type ndx = whefs_inode_hash_cache_search_ndx( fs, oldName ? oldName : name ); | | | 139 | if( whefs_rc.OK == whefs_inode_search_opened( fs, nid, &nop ) ) |
| | | 140 | { // FIXME: this is unfortunate. TODO: remove whefs_inode::name altogether. | ||
| | | 141 | whefs_string_copy_cstring( &nop->name, name ); | ||
| | | 142 | } | ||
| | | 143 | #endif | ||
| | | 144 | |||
| | | 145 | WHEFS_DBG_CACHE("inode-name-set searching for [old=%s][new=%s][check=%s].",ncheck.string,name,nameCheck); | ||
| | | 146 | whefs_id_type ndx = whefs_inode_hash_cache_search_ndx( fs, nameCheck ); | ||
| 120 | if( ndx != whefs_id_type_end ) | 147 | if( ndx != whefs_id_type_end ) | |
| 121 | { | 148 | { | |
| > | 149 | WHEFS_DBG_CACHE("inode-name-set found an existing entry for [%s].",nameCheck); | ||
| 122 | H = &fs->cache.hashes->list[ndx]; | 150 | H = &fs->cache.hashes->list[ndx]; | |
| 123 | if( H->id != nid ) | 151 | if( H->id != nid ) | |
| 124 | { | 152 | { | |
| 125 | WHEFS_DBG_ERR("Internal error: cache hash collision for name [%s]!",name); | 153 | WHEFS_DBG_ERR("Internal error: cache hash collision for name [%s]!",name); | |
| 126 | return whefs_rc.InternalError; | 154 | return whefs_rc.InternalError; | |
| 127 | } | 155 | } | |
| 128 | if( whefs_rc.OK == whefs_inode_search_opened( fs, nid, &nop ) ) | < | ||
| 129 | { // this is unfortunate. TODO: remove whefs_inode::name altogether. | < | ||
| 130 | whefs_string_copy_cstring( &nop->name, name ); | < | ||
| 131 | } | < | ||
| 132 | } | 156 | } | |
| 133 | #endif | < | ||
| 134 | /** | 157 | /** | |
| 135 | Maintenance reminders: | 158 | Maintenance reminders: | |
| 136 | 159 | |||
| 137 | We write to disk before updating any opened inode because writing is | 160 | We write to disk before updating any opened inode because writing is | |
| 138 | much more likely to fail then updating the opened inode is, since the latter | 161 | much more likely to fail then updating the opened inode is, since the latter | |
| 6 hidden lines | ||||
| 145 | if( whefs_rc.OK != rc ) return rc; | 168 | if( whefs_rc.OK != rc ) return rc; | |
| 146 | #if 1 | 169 | #if 1 | |
| 147 | if( H ) | 170 | if( H ) | |
| 148 | { | 171 | { | |
| 149 | H->hash = fs->cache.hashfunc(name); | 172 | H->hash = fs->cache.hashfunc(name); | |
| 150 | fs->cache.hashes->isSorted = false; | | | 173 | //fs->cache.hashes->isSorted = false; |
| 151 | if(1) WHEFS_DBG("Replacing hashcode for file [%s].",name); | | | 174 | whefs_hashid_list_sort( fs->cache.hashes ); |
| 152 | rc = whefs_string_copy_cstring( &nop->name, name ); | | | 175 | WHEFS_DBG_CACHE("Replacing hashcode for file [%s].",name); |
| | | 176 | if( nop ) | ||
| | | 177 | { | ||
| | | 178 | rc = whefs_string_copy_cstring( &nop->name, name ); | ||
| | | 179 | } | ||
| 153 | } | 180 | } | |
| 154 | if( whefs_rc.OK != rc ) return rc; | 181 | if( whefs_rc.OK != rc ) return rc; | |
| 155 | whefs_string_db_set( &fs->cache.strings, nid-1, name ); | | | 182 | whefs_string_cache_set( &fs->cache.strings, nid-1, name ); |
| 156 | #endif | 183 | #endif | |
| 157 | return rc; | 184 | return rc; | |
| 158 | } | 185 | } | |
| 159 | 186 | |||
| 160 | #if ! WHEFS_MACROIZE_SMALL_CHECKS | 187 | #if ! WHEFS_MACROIZE_SMALL_CHECKS | |
| 58 hidden lines | ||||
| 219 | } | 246 | } | |
| 220 | 247 | |||
| 221 | int whefs_inode_id_read( whefs_fs * fs, whefs_id_type nid, whefs_inode * tgt ) | 248 | int whefs_inode_id_read( whefs_fs * fs, whefs_id_type nid, whefs_inode * tgt ) | |
| 222 | { | 249 | { | |
| 223 | if( !tgt || !whefs_inode_id_is_valid( fs, nid ) ) return whefs_rc.ArgError; | 250 | if( !tgt || !whefs_inode_id_is_valid( fs, nid ) ) return whefs_rc.ArgError; | |
| 224 | if(1) | | | 251 | if( WHEFS_CONFIG_ENABLE_STRINGS_CACHE ) |
| 225 | { | 252 | { | |
| 226 | whefs_inode * nop = 0; | 253 | whefs_inode * nop = 0; | |
| 227 | int xc = whefs_inode_search_opened( fs, nid, &nop ); | 254 | int xc = whefs_inode_search_opened( fs, nid, &nop ); | |
| 228 | if( (whefs_rc.OK == xc) && nop ) | 255 | if( (whefs_rc.OK == xc) && nop ) | |
| 229 | { | 256 | { | |
| 423 hidden lines | ||||
| 653 | } | 680 | } | |
| 654 | } | 681 | } | |
| 655 | #endif | 682 | #endif | |
| 656 | 683 | |||
| 657 | whefs_string ns = whefs_string_init; | 684 | whefs_string ns = whefs_string_init; | |
| 658 | int rc = 0; | | | 685 | int rc = whefs_rc.OK; |
| 659 | bool expectExact = false; // when true, we stop with error if first guess isn't correct | 686 | bool expectExact = false; // when true, we stop with error if first guess isn't correct | |
| 660 | const whefs_hashval_type nameHash = fs->cache.hashfunc( name ); | 687 | const whefs_hashval_type nameHash = fs->cache.hashfunc( name ); | |
| 661 | #if 1 | 688 | #if 1 | |
| 662 | if( fs->cache.hashes && !fs->cache.hashes->isSorted ) | 689 | if( fs->cache.hashes && !fs->cache.hashes->isSorted ) | |
| 663 | { | 690 | { | |
| 7 hidden lines | ||||
| 671 | i = 2; // 2 = first client-usable inode. | 698 | i = 2; // 2 = first client-usable inode. | |
| 672 | } | 699 | } | |
| 673 | else | 700 | else | |
| 674 | { // we know directly what inode record to jump to now... | 701 | { // we know directly what inode record to jump to now... | |
| 675 | expectExact = true; | 702 | expectExact = true; | |
| 676 | if(0) WHEFS_DBG("Filename matched cached INDEX (%"WHEFS_ID_TYPE_PFMT") for hash code 0x%"WHEFS_HASHVAL_TYPE_PFMT" for name [%s]",i, nameHash,name); | | | 703 | if(0) WHEFS_DBG_CACHE("Filename matched cached INDEX (%"WHEFS_ID_TYPE_PFMT") for hash code 0x%"WHEFS_HASHVAL_TYPE_PFMT" for name [%s]",i, nameHash,name); |
| 677 | whefs_hashid * H = &fs->cache.hashes->list[i]; | 704 | whefs_hashid * H = &fs->cache.hashes->list[i]; | |
| 678 | ++H->hits; | 705 | ++H->hits; | |
| 679 | i = H->id; | 706 | i = H->id; | |
| 680 | cname = whefs_string_db_get( &fs->cache.strings, i-1 ); | | | 707 | if( WHEFS_CONFIG_ENABLE_STRINGS_CACHE ) |
| 681 | if(0) WHEFS_DBG("Got cached ID (%"WHEFS_ID_TYPE_PFMT") for hash code 0x%"WHEFS_HASHVAL_TYPE_PFMT" for name [%s]/[%s] hit count=[%"PRIu32"]",i, nameHash,name,cname,H->hits); | | | ||
| 682 | if( !cname ) | | | ||
| 683 | { | 708 | { | |
| 684 | WHEFS_DBG("Internal consistency/usage error: hash cache has inode entry #%"WHEFS_ID_TYPE_PFMT" cached for name [%s] but names db does not have an entry!", | | | 709 | cname = whefs_string_cache_get( &fs->cache.strings, i-1 ); |
| 685 | i, name ); | | | 710 | if(0) WHEFS_DBG_CACHE("Got cached ID (%"WHEFS_ID_TYPE_PFMT") for hash code 0x%"WHEFS_HASHVAL_TYPE_PFMT" for name [%s]/[%s] hit count=[%"PRIu32"]",i, nameHash,name,cname,H->hits); |
| 686 | return whefs_rc.InternalError; | | | 711 | if( !cname ) |
| | | 712 | { | ||
| | | 713 | WHEFS_DBG_ERR("Internal consistency/usage error: hash cache has inode entry #%"WHEFS_ID_TYPE_PFMT" cached for name [%s] but names db does not have an entry!", | ||
| | | 714 | i, name ); | ||
| | | 715 | return whefs_rc.InternalError; | ||
| | | 716 | } | ||
| | | 717 | //rc = whefs_rc.OK; | ||
| | | 718 | // FIXME: either remove whefs_inode::name (replaced with the name cache) | ||
| | | 719 | // or search for opened node here where id==H->id and use that name, | ||
| | | 720 | // if it's set. (The plan is to try to phase out inode.name first.). | ||
| 687 | } | 721 | } | |
| 688 | rc = whefs_rc.OK; | < | ||
| 689 | // FIXME: either remove whefs_inode::name (replaced with the name cache) | < | ||
| 690 | // or search for opened node here where id==H->id and use that name, | < | ||
| 691 | // if it's set. (The plan is to try to phase out inode.name first.). | < | ||
| 692 | } | 722 | } | |
| 693 | 723 | |||
| 694 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | 724 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH+1 }; | |
| 695 | unsigned char buf[bufSize] = {0}; | 725 | unsigned char buf[bufSize] = {0}; | |
| 696 | if( ! cname ) | 726 | if( ! cname ) | |
| 113 hidden lines | ||||
| 810 | x += whefs_sizeof_encoded_uint32; | 840 | x += whefs_sizeof_encoded_uint32; | |
| 811 | rc = whefs_id_decode( x, &dest->first_block ); | 841 | rc = whefs_id_decode( x, &dest->first_block ); | |
| 812 | return rc; | 842 | return rc; | |
| 813 | } | 843 | } | |
| 814 | 844 | |||
Changes to whefs_inode.h
| Old (e03f2910a9761dd2) | New (5d5be8cd2a102fc6) | |||
|---|---|---|---|---|
| 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED) | 1 | #if !defined(WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED) | |
| 2 | #define WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED 1 | 2 | #define WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED 1 | |
| 3 | /* | 3 | /* | |
| 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | 4 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/ | |
| 5 | 5 | |||
| 453 hidden lines | ||||
| 459 | 459 | |||
| 460 | /** | 460 | /** | |
| 461 | Loads the name for the given inode id into the given target string | 461 | Loads the name for the given inode id into the given target string | |
| 462 | (which may not be null). If tgt has memory allocated to it, it may | 462 | (which may not be null). If tgt has memory allocated to it, it may | |
| 463 | be re-used (or realloc()'d) by this function, so the caller must | 463 | be re-used (or realloc()'d) by this function, so the caller must | |
| 464 | copy it beforehand if it will be needed later. If the read-in | | | 464 | copy it beforehand if the existing value will be needed later. If the read-in |
| 465 | string has a length of 0 and tgt->alloced is not 0 (i.e. tgt | 465 | string has a length of 0 and tgt->alloced is not 0 (i.e. tgt | |
| 466 | already has content), then the string's memory is kept but is | 466 | already has content), then the string's memory is kept but is | |
| 467 | zeroed out and tgt->length will be set to 0. | 467 | zeroed out and tgt->length will be set to 0. | |
| 468 | 468 | |||
| 469 | Returns whefs_rc.OK on success. | 469 | Returns whefs_rc.OK on success. | |
| > | 470 | |||
| > | 471 | If you want to ensure that no call to malloc() or realloc() is made | ||
| > | 472 | to expand tgt, yet still be assured of having enough memory available | ||
| > | 473 | to store the string, here's a trick: | ||
| > | 474 | |||
| > | 475 | @code | ||
| > | 476 | enum { bufSize = WHEFS_MAX_FILENAME_LENGTH + 1 }; | ||
| > | 477 | char buf[bufSize] = {0}; | ||
| > | 478 | whefs_string str = whefs_string_init; | ||
| > | 479 | str.string = buf; | ||
| > | 480 | str.alloced = bufSize; | ||
| > | 481 | int rc = whefs_inode_name_get( fs, id, &str ); | ||
| > | 482 | assert( (str.string == buf) && "Illegal (re)alloc!" ); | ||
| > | 483 | ... | ||
| > | 484 | @endcode | ||
| > | 485 | |||
| > | 486 | The internals of the lib won't allow an inode name longer than | ||
| > | 487 | fs->options.filename_length, which must be less than or equal to | ||
| > | 488 | WHEFS_MAX_FILENAME_LENGTH. We add one to the maximum buffer size in | ||
| > | 489 | the above code to accommodate the trailing null. | ||
| 470 | */ | 490 | */ | |
| 471 | int whefs_inode_name_get( whefs_fs * fs, whefs_id_type id, whefs_string * tgt ); | 491 | int whefs_inode_name_get( whefs_fs * fs, whefs_id_type id, whefs_string * tgt ); | |
| 472 | 492 | |||
| 473 | 493 | |||
| 474 | /** | 494 | /** | |
| 71 hidden lines | ||||
| 546 | decoding fails then whefs_rc.ConsistencyError is returned. | 566 | decoding fails then whefs_rc.ConsistencyError is returned. | |
| 547 | */ | 567 | */ | |
| 548 | int whefs_inode_decode( whefs_inode * dest, unsigned char const * src ); | 568 | int whefs_inode_decode( whefs_inode * dest, unsigned char const * src ); | |
| 549 | 569 | |||
| 550 | /** | 570 | /** | |
| 551 | A functor for use with whefs_inode_foreach(). n is the current inode | | | 571 | whefs_inode_foreach_f describes a functor for use with |
| | | 572 | whefs_inode_foreach(). n is the current inode being iterated | ||
| | | 573 | over. clientData is the client-determined argument passed to | ||
| | | 574 | whefs_inode_foreach(). | ||
| 552 | */ | 575 | */ | |
| 553 | typedef int (*whefs_inode_foreach_f)( whefs_fs * fs, whefs_inode const * n, void * clientData ); | 576 | typedef int (*whefs_inode_foreach_f)( whefs_fs * fs, whefs_inode const * n, void * clientData ); | |
| 554 | /** | 577 | /** | |
| 555 | | | 578 | whefs_inode_predicate_f describes a predicate functor for use with | |
| | | 579 | whefs_inode_foreach(). n is the current inode being iterated | ||
| | | 580 | over. clientData is the client-determined argument passed to | ||
| | | 581 | whefs_inode_foreach(). | ||
| 556 | */ | 582 | */ | |
| 557 | typedef bool (*whefs_inode_predicate_f)( whefs_fs * fs, whefs_inode const * n, void * clientData ); | 583 | typedef bool (*whefs_inode_predicate_f)( whefs_fs * fs, whefs_inode const * n, void * clientData ); | |
| 558 | 584 | |||
| 559 | /** | 585 | /** | |
| 560 | Walks each inode in fs, starting at inode #2 (#1 is reserved for | 586 | Walks each inode in fs, starting at inode #2 (#1 is reserved for | |
| 561 | internal use as the root node). For each node, where(node,whereData) is called. | | | 587 | internal use as the root node). For each node, whereFunc(node,whereData) is called. |
| 562 | If it returns true then forEach(fs,n,forEachData) is called. If forEach() returns | 588 | If it returns true then forEach(fs,n,forEachData) is called. If forEach() returns | |
| 563 | any value other than whefs_rc.OK then looping stops and that code is returned. | 589 | any value other than whefs_rc.OK then looping stops and that code is returned. | |
| 564 | 590 | |||
| 565 | The where function may be null but forEach may not. If where is | | | 591 | The whereFunc function may be null but forEach may not. If whereFunc is |
| 566 | null then it is treated as always returning true. The whereData and | 592 | null then it is treated as always returning true. The whereData and | |
| 567 | forEachData pointers may be anything - they are passed as-is to the | 593 | forEachData pointers may be anything - they are passed as-is to the | |
| 568 | where/forEach functions. | | | 594 | whereFunc/forEach functions. |
| 569 | 595 | |||
| 570 | On success, whefs_rc.OK is returned. The other failure cases are: | 596 | On success, whefs_rc.OK is returned. The other failure cases are: | |
| 571 | 597 | |||
| 572 | - fs or forEach are null: whefs_rc.ArgError | 598 | - fs or forEach are null: whefs_rc.ArgError | |
| 573 | 599 | |||
| 3 hidden lines | ||||
| 577 | would grow exponentially as the number of opened inodes grew). Thus | 603 | would grow exponentially as the number of opened inodes grew). Thus | |
| 578 | care must be taken with the nodes passed on to forEach, lest any | 604 | care must be taken with the nodes passed on to forEach, lest any | |
| 579 | changes made to them get overwritten by the opened node when it | 605 | changes made to them get overwritten by the opened node when it | |
| 580 | flushes. | 606 | flushes. | |
| 581 | */ | 607 | */ | |
| 582 | int whefs_inode_foreach( whefs_fs * fs, whefs_inode_predicate_f where, void * whereData, whefs_inode_foreach_f forEach, void * forEachData ); | | | 608 | int whefs_inode_foreach( whefs_fs * fs, whefs_inode_predicate_f whereFunc, void * whereData, whefs_inode_foreach_f forEach, void * forEachData ); |
| 583 | 609 | |||
| 584 | #ifdef __cplusplus | 610 | #ifdef __cplusplus | |
| 585 | } /* extern "C" */ | 611 | } /* extern "C" */ | |
| 586 | #endif | 612 | #endif | |
| 587 | 613 | |||
| 588 | 614 | |||
| 589 | #endif /* WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED */ | 615 | #endif /* WANDERINGHORSE_NET_WHEFS_INODE_H_INCLUDED */ | |