xref: /haiku/src/tests/add-ons/kernel/file_systems/bfs/btree/cache.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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