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
30static size_t sBlockSize;
31
32
33BList gBlocks;
34
35
36void
37init_cache(BFile* /*file*/, int32 blockSize)
38{
39	sBlockSize = blockSize;
40}
41
42
43void
44shutdown_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
59status_t
60cached_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
78static status_t
79read_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
96static void*
97get_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
107static void
108release_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
117const void*
118block_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
125status_t
126block_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
136void*
137block_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
146status_t
147block_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
161void
162block_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