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
init_cache(BFile *,int32 blockSize)37 init_cache(BFile* /*file*/, int32 blockSize)
38 {
39 sBlockSize = blockSize;
40 }
41
42
43 void
shutdown_cache(BFile * file,int32 blockSize)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
cached_write(void * cache,off_t num,const void * _data,off_t numBlocks)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
read_blocks(void * cache,off_t num)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*
get_block(void * cache,off_t num)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
release_block(void * cache,off_t num)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*
block_cache_get(void * _cache,off_t blockNumber)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
block_cache_make_writable(void * _cache,off_t blockNumber,int32 transaction)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*
block_cache_get_writable(void * _cache,off_t blockNumber,int32 transaction)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
block_cache_set_dirty(void * _cache,off_t blockNumber,bool dirty,int32 transaction)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
block_cache_put(void * _cache,off_t blockNumber)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