1 /* cache - emulation for the B+Tree torture test 2 ** 3 ** Initial version by Axel Dörfler, axeld@pinc-software.de 4 ** This file may be used under the terms of the MIT License. 5 */ 6 7 8 #include "cache.h" 9 10 #include "BPlusTree.h" 11 // To get at the right debug helpers 12 13 #include <File.h> 14 #include <List.h> 15 16 #include <malloc.h> 17 #include <stdio.h> 18 19 20 /* A note from the author: this cache implementation can only be used 21 * with the test program, it really suites no other needs. 22 * It's very simple and not that efficient, and simple holds the whole 23 * file in memory, all the time. 24 */ 25 26 27 #define TRACE(x) /*printf x*/ 28 29 30 static size_t sBlockSize; 31 32 33 BList gBlocks; 34 35 36 void 37 init_cache(BFile* /*file*/, int32 blockSize) 38 { 39 sBlockSize = blockSize; 40 } 41 42 43 void 44 shutdown_cache(BFile* file, int32 blockSize) 45 { 46 for (int32 i = 0; i < gBlocks.CountItems(); i++) { 47 void* buffer = gBlocks.ItemAt(i); 48 if (buffer == NULL) { 49 debugger("cache is corrupt!"); 50 exit(-1); 51 } 52 53 file->WriteAt(i * blockSize, buffer, blockSize); 54 free(buffer); 55 } 56 } 57 58 59 status_t 60 cached_write(void* cache, off_t num, const void* _data, off_t numBlocks) 61 { 62 if (num + numBlocks > gBlocks.CountItems()) { 63 debugger("cached write beyond loaded blocks"); 64 exit(1); 65 } 66 67 for (off_t i = 0; i < numBlocks; i++) { 68 void* buffer = gBlocks.ItemAt(num + i); 69 const void* data = (uint8*)_data + i * sBlockSize; 70 if (buffer != data) 71 memcpy(buffer, data, sBlockSize); 72 } 73 74 return B_OK; 75 } 76 77 78 static status_t 79 read_blocks(void* cache, off_t num) 80 { 81 BFile* file = (BFile*)cache; 82 for (uint32 i = gBlocks.CountItems(); i <= num; i++) { 83 void* buffer = malloc(sBlockSize); 84 if (buffer == NULL) 85 return B_NO_MEMORY; 86 87 gBlocks.AddItem(buffer); 88 if (file->ReadAt(i * sBlockSize, buffer, sBlockSize) < 0) 89 return B_IO_ERROR; 90 } 91 92 return B_OK; 93 } 94 95 96 static void* 97 get_block(void* cache, off_t num) 98 { 99 //TRACE(("get_block(num = %" B_PRIdOFF ")\n", num); 100 if (num >= gBlocks.CountItems()) 101 read_blocks(cache, num); 102 103 return gBlocks.ItemAt(num); 104 } 105 106 107 static void 108 release_block(void* cache, off_t num) 109 { 110 //TRACE(("release_block(num = %" B_PRIdOFF ")\n", num)); 111 } 112 113 114 // #pragma mark - Block Cache API 115 116 117 const void* 118 block_cache_get(void* _cache, off_t blockNumber) 119 { 120 TRACE(("block_cache_get(block = %" B_PRIdOFF ")\n", blockNumber)); 121 return get_block(_cache, blockNumber); 122 } 123 124 125 status_t 126 block_cache_make_writable(void* _cache, off_t blockNumber, int32 transaction) 127 { 128 TRACE(("block_cache_make_writable(block = %" B_PRIdOFF ", transaction = %" 129 B_PRId32 ")\n", blockNumber, transaction)); 130 131 // We're always writable... 132 return B_OK; 133 } 134 135 136 void* 137 block_cache_get_writable(void* _cache, off_t blockNumber, int32 transaction) 138 { 139 TRACE(("block_cache_get_writable(block = %" B_PRIdOFF 140 ", transaction = %" B_PRId32 ")\n", blockNumber, transaction)); 141 return get_block(_cache, blockNumber); 142 } 143 144 145 146 status_t 147 block_cache_set_dirty(void* _cache, off_t blockNumber, bool dirty, 148 int32 transaction) 149 { 150 TRACE(("block_cache_set_dirty(block = %" B_PRIdOFF 151 ", dirty = %s, transaction = %" B_PRId32 ")\n", blockNumber, 152 dirty ? "yes" : "no", transaction)); 153 154 if (dirty) 155 debugger("setting to dirty not implemented\n"); 156 157 return B_OK; 158 } 159 160 161 void 162 block_cache_put(void* _cache, off_t blockNumber) 163 { 164 TRACE(("block_cache_put(block = %" B_PRIdOFF ")\n", blockNumber)); 165 release_block(_cache, blockNumber); 166 } 167