Subversion Repositories Code-Repo

Rev

Rev 96 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
96 Kevin 1
import java.io.BufferedWriter;
2
import java.io.FileNotFoundException;
3
import java.io.FileWriter;
4
import java.io.IOException;
5
import java.io.RandomAccessFile;
6
 
7
public class LRUBuffer {
8
 
9
	private int blockSize = 0;
10
 
11
	private int cacheHit = 0;
12
	private int cacheMiss = 0;
13
	private int diskReads = 0;
14
	private int diskWrites = 0;
15
 
16
	private String dataFile;
17
	private String statFile;
18
 
19
	private BufferBlock bufferHead;
20
 
21
	private RandomAccessFile file;
22
 
23
	public LRUBuffer(String datafile, String statfile, int size, int blocksize) {
24
		this.dataFile = datafile;
25
		this.statFile = statfile;
26
		this.blockSize = blocksize;
27
 
28
		// Allocates a new doubly linked list of BufferBlocks
29
		// The buffer will have at least one block
30
		bufferHead = new BufferBlock(blockSize);
31
		BufferBlock cur = bufferHead;
32
		for (int i = 0; i < size-1; i++) {
33
			BufferBlock newBlock = new BufferBlock(blockSize);
34
			cur.setNext(newBlock);
35
			newBlock.setPrev(cur);
36
			cur = newBlock;
37
		}
38
 
39
		// Open access to the datafile
40
		try {
41
			file = new RandomAccessFile(dataFile, "rw");
42
			file.setLength(0);
43
		} catch (FileNotFoundException e) {
44
			e.printStackTrace();
45
		} catch (IOException e) {
46
			e.printStackTrace();
47
		}
48
	}
49
 
50
	/** Recursive function to copy length number of bytes from file at startAddress
51
	 * to offset position in out
52
	 * 
53
	 * @param out Destination array to copy bytes to
54
	 * @param offset Offset of position to write to in the destination array
55
	 * @param startAddress Starting address on disk to copy bytes from
56
	 * @param length Number of bytes to copy to the destination array
57
	 * @return
58
	 */
59
	public boolean getBytes(byte[] out, int offset, long startAddress, int length) {
60
		BufferBlock cur = bufferHead;
61
 
62
		// If the requested length doesnt extends to the next block
63
		if (startAddress % blockSize + length < blockSize) {
64
			// Check if address is already in a buffer block
65
			while (cur != null && cur.getStartAddress() != -1) {
66
				if (startAddress >= cur.getStartAddress() && startAddress < cur.getStartAddress() + blockSize) {
67
					// Address is in block
68
					cacheHit++;
69
					// Bring current block to front of list
70
					bringToFront(cur);
71
					// Get data
72
					cur.getBytes(out, offset, (int)startAddress % blockSize, length);
73
					return true;
74
				}
75
				cur = cur.getNext();
76
			}
77
 
78
			// Address is not in buffer, read new block from disk
79
			cacheMiss++;
80
			cur = readFromDisk(startAddress);
81
			insertToFront(cur);
82
			// Get data from block
83
			cur.getBytes(out, offset, (int)startAddress % blockSize, length);
84
			return true;
85
		// If the requested length extends to the next block
86
		} else {
87
			int bytesToRead = 0;
88
			// Check if address is already in a buffer block
89
			while (cur != null && cur.getStartAddress() != -1) {
90
				if (startAddress >= cur.getStartAddress() && startAddress < cur.getStartAddress() + blockSize) {
91
					// Address is in block
92
					cacheHit++;
93
					// Bring current block to front of list
94
					bringToFront(cur);
95
					// Read in from address to end of block
96
					bytesToRead = blockSize - (int)startAddress % blockSize;
97
					cur.getBytes(out, offset, (int)startAddress % blockSize, bytesToRead);
98
					offset += bytesToRead;
99
					// Get data from the next consecutive block
100
					getBytes(out, offset, startAddress + bytesToRead, length - bytesToRead);
101
					return true;
102
				}
103
				cur = cur.getNext();
104
			}
105
 
106
			// Address is not in buffer, read new block from disk
107
			cacheMiss++;
108
			cur = readFromDisk(startAddress);
109
			insertToFront(cur);
110
			// Read in from address to end of block
111
			bytesToRead = blockSize - (int)startAddress % blockSize;
112
			cur.getBytes(out, offset, (int)startAddress % blockSize, bytesToRead);
113
			offset += bytesToRead;
114
			// Get data from the next consecutive block
115
			getBytes(out, offset, startAddress + bytesToRead, length - bytesToRead);
116
			return true;
117
		}
118
	}
119
 
120
	/** Recursive function to copy length number of bytes from in to file at startAddress
121
	 * 
122
	 * @param in Input array to copy bytes from
123
	 * @param startAddress Starting address on disk to copy bytes to
124
	 * @param length Number of bytes to copy from in to disk
125
	 * @return
126
	 */
127
	public boolean putBytes(byte[] in, int offset, long startAddress, int length) {
128
		BufferBlock cur = bufferHead;
129
 
130
		// If the requested length doesnt extends to the next block
131
		if (startAddress % blockSize + length <= blockSize) {
132
			// Check if address is already in a buffer block
133
			while (cur != null && cur.getStartAddress() != -1) {
134
				if (startAddress >= cur.getStartAddress() && startAddress < cur.getStartAddress() + blockSize) {
135
					// Address is in block
136
					cacheHit++;
137
					// Bring current block to front of list
138
					bringToFront(cur);
139
					// Put data into block
140
					cur.setBytes(in, offset, (int)startAddress % blockSize, length);
141
					cur.setDirtyBit(true);
142
					return true;
143
				}
144
				cur = cur.getNext();
145
			}
146
 
147
			// Address is not in buffer, read new block from disk
148
			cacheMiss++;
149
			cur = readFromDisk(startAddress);
150
			insertToFront(cur);
151
			// Put data into block
152
			cur.setBytes(in, offset, (int)startAddress % blockSize, length);
153
			cur.setDirtyBit(true);
154
			return true;
155
		// If the requested length extends to the next block
156
		} else {
157
			int bytesToWrite = 0;
158
			// Check if address is already in a buffer block
159
			while (cur != null && cur.getStartAddress() != -1) {
160
				if (startAddress >= cur.getStartAddress() && startAddress < cur.getStartAddress() + blockSize) {
161
					// Address is in block
162
					cacheHit++;
163
					// Bring current block to front of list
164
					bringToFront(cur);
165
					// Put in data until end of block
166
					bytesToWrite = blockSize - (int)startAddress % blockSize;
167
					cur.setBytes(in, offset, (int)startAddress % blockSize, bytesToWrite);
168
					cur.setDirtyBit(true);
169
					startAddress += bytesToWrite;
170
					// Put remaining data into the next consecutive block
171
					putBytes(in, offset + bytesToWrite, startAddress, length - bytesToWrite);
172
					return true;
173
				}
174
				cur = cur.getNext();
175
			}
176
 
177
			// Address is not in buffer, read new block from disk
178
			cacheMiss++;
179
			cur = readFromDisk(startAddress);
180
			insertToFront(cur);
181
			// Put in data until end of block
182
			bytesToWrite = blockSize - (int)startAddress % blockSize;
183
			cur.setBytes(in, offset, (int)startAddress % blockSize, bytesToWrite);
184
			cur.setDirtyBit(true);
185
			startAddress += bytesToWrite;
186
			// Put remaining data into the next consecutive block
187
			putBytes(in, offset + bytesToWrite, startAddress, length - bytesToWrite);
188
			return true;
189
		}
190
	}
191
 
192
	/** Brings a block currently in the list to the front of the list */
193
	private void bringToFront(BufferBlock block) {
194
		// If block is already in front, return
195
		if (block == bufferHead)
196
			return;
197
 
198
		if (block.getPrev() != null)
199
			block.getPrev().setNext(block.getNext());
200
		if (block.getNext() != null)
201
			block.getNext().setPrev(block.getPrev());
202
		block.setPrev(null);
203
		bufferHead.setPrev(block);
204
		block.setNext(bufferHead);
205
		bufferHead = block;
206
	}
207
 
208
	/** Inserts a new block into the front of the list */
209
	private void insertToFront(BufferBlock block) {
210
		// Set head as current block
211
		block.setPrev(null);
212
		bufferHead.setPrev(block);
213
		block.setNext(bufferHead);
214
		bufferHead = block;
215
		// Write last block in list to disk if dirty bit is set
216
		// Last block is also removed
217
		BufferBlock cur = bufferHead;
218
		while (cur.getNext() != null) {
219
			cur = cur.getNext();
220
		}
221
		cur.getPrev().setNext(null);
222
		if (cur.isDirtyBit()) {
223
			writeToDisk(cur);
224
		}
225
	}
226
 
227
	/** Reads a new block from disk given an address */
228
	private BufferBlock readFromDisk(long address) {
229
		diskReads++;
230
		byte[] data = new byte[blockSize];
231
		long offset = address / blockSize;
232
		offset = offset * blockSize;
233
		try {
234
			file.seek(offset);
235
			file.read(data);
236
		} catch (IOException e) {
237
			e.printStackTrace();
238
		}
239
 
240
		// Pass read block into a new block
241
		BufferBlock newBlock = new BufferBlock(blockSize);
242
		newBlock.setBytes(data, 0, 0, blockSize);
243
		newBlock.setStartAddress(offset);
244
 
245
		return newBlock;
246
	}
247
 
248
	/** Writes the specified block to disk */
249
	private void writeToDisk(BufferBlock block) {
250
		diskWrites++;
251
		byte[] data = new byte[blockSize];
252
		block.getBytes(data, 0, 0, blockSize);
253
		try {
254
			file.seek(block.getStartAddress());
255
			file.write(data);
256
		} catch (IOException e) {
257
			e.printStackTrace();
258
		}
259
	}
260
 
261
	/** Flush the buffer by writing all blocks in buffer to disk */
262
	public void flushBuffer() {
263
		BufferBlock cur = bufferHead;
264
		while (cur != null) {
265
			if (cur.isDirtyBit()) {
266
				writeToDisk(cur);
267
			}
268
			cur = cur.getNext();
269
		}
270
 
271
		try {
272
			file.close();
273
		} catch (IOException e) {
274
			e.printStackTrace();
275
		}
276
	}
277
 
278
	/** Write stats to stat file */
279
	public void writeStats(long time) {
280
		try {
281
			BufferedWriter out = new BufferedWriter(new FileWriter(statFile, true));
282
			StringBuilder str = new StringBuilder();
283
			str.append("Datafile: " + dataFile + " | ");
284
			str.append("Cache Hits: " + cacheHit + " | ");
285
			str.append("Cache Misses: " + cacheMiss + " | ");
286
			str.append("Disk Reads: " + diskReads + " | ");
287
			str.append("Disk Writes: " + diskWrites + " | ");
288
			str.append("Time to Sort: " + time + "\n");
289
			out.write(str.toString());
290
			out.close();
291
		} catch (IOException e) {
292
			e.printStackTrace();
293
		}
294
	}
295
 
296
	public void printBlockIDs() {
297
		BufferBlock cur = bufferHead;
298
		System.out.print("Buffer Pool Blocks: ");
299
		while (cur != null && cur.getStartAddress() != -1) {
300
//			System.out.print(cur.getStartAddress() + " ; ");
301
			System.out.print(cur.getStartAddress() / blockSize + " ; ");
302
			cur = cur.getNext();
303
		}
304
		System.out.print("\n");
305
	}
306
}