Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
95 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
	private int recordSize = 0;
11
 
12
	private int cacheHit = 0;
13
	private int cacheMiss = 0;
14
	private int diskReads = 0;
15
	private int diskWrites = 0;
16
 
17
	private String dataFile;
18
	private String statFile;
19
	private int bufferSize;
20
 
21
	private BufferBlock bufferHead;
22
 
23
	private RandomAccessFile file;
24
 
25
	public LRUBuffer(String datafile, String statfile, int size, int blocksize, int recordsize) {
26
		this.dataFile = datafile;
27
		this.statFile = statfile;
28
		this.bufferSize = size;
29
		this.blockSize = blocksize;
30
		this.recordSize = recordsize;
31
 
32
		// Allocates a new doubly linked list of BufferBlocks
33
		// The buffer will have at least one block
34
		bufferHead = new BufferBlock(blockSize);
35
		BufferBlock cur = bufferHead;
36
		for (int i = 0; i < size-1; i++) {
37
			BufferBlock newBlock = new BufferBlock(blockSize);
38
			cur.setNext(newBlock);
39
			newBlock.setPrev(cur);
40
			cur = newBlock;
41
		}
42
 
43
		// Open access to the datafile
44
		try {
45
			file = new RandomAccessFile(dataFile, "rw");
46
		} catch (FileNotFoundException e) {
47
			e.printStackTrace();
48
		}
49
	}
50
 
51
	// Returns recordSize number of bytes to out from record # pos
52
	public boolean getBytes(byte[] out, long pos) {
53
		BufferBlock cur = bufferHead;
54
 
55
		// Calculate the address of record
56
		long address = pos * recordSize;
57
 
58
		// Check if address is already in a buffer block
59
		while (cur != null && cur.getStartAddress() != -1) {
60
			if (address >= cur.getStartAddress() && address < cur.getStartAddress() + blockSize) {
61
				// Address is in block, get data
62
				cacheHit++;
63
				cur.getBytes(out, (int)address % blockSize, recordSize);
64
				// Bring current block to front of list
65
				bringToFront(cur);
66
				return true;
67
			}
68
			cur = cur.getNext();
69
		}
70
 
71
		// Address is not in buffer, read new block from disk
72
		cacheMiss++;
73
		BufferBlock newBlock = readFromDisk(address);
74
		// Get requested bytes from block
75
		newBlock.getBytes(out, (int)address % blockSize, recordSize);
76
		insertToFront(newBlock);
77
		return false;
78
	}
79
 
80
	// Puts recordSize number of bytes from in to record # pos
81
	public boolean putBytes(byte[] in, long pos) {
82
		BufferBlock cur = bufferHead;
83
 
84
		// Calculate the address of record
85
		long address = pos * recordSize;
86
 
87
		// Check if address is already in a buffer block
88
		while (cur != null && cur.getStartAddress() != -1) {
89
			if (address >= cur.getStartAddress() && address < cur.getStartAddress() + blockSize) {
90
				// Address is in block, put data
91
				cacheHit++;
92
				cur.setBytes(in, (int)address % blockSize, recordSize);
93
				cur.setDirtyBit(true);
94
				// Bring current block to front of list
95
				bringToFront(cur);
96
				return true;
97
			}
98
			cur = cur.getNext();
99
		}
100
 
101
		// Address is not in buffer, read new block from disk
102
		cacheMiss++;
103
		BufferBlock newBlock = readFromDisk(address);
104
		// Put passed bytes into block
105
		newBlock.setBytes(in, (int)address % blockSize, recordSize);
106
		newBlock.setDirtyBit(true);
107
		insertToFront(newBlock);
108
		return false;
109
	}
110
 
111
	// Brings a block currently in the list to the front of the list
112
	private void bringToFront(BufferBlock block) {
113
		// If block is already in front, return
114
		if (block == bufferHead)
115
			return;
116
 
117
		if (block.getPrev() != null)
118
			block.getPrev().setNext(block.getNext());
119
		if (block.getNext() != null)
120
			block.getNext().setPrev(block.getPrev());
121
		block.setPrev(null);
122
		bufferHead.setPrev(block);
123
		block.setNext(bufferHead);
124
		bufferHead = block;
125
	}
126
 
127
	// Inserts a new block into the front of the list
128
	private void insertToFront(BufferBlock block) {
129
		// Set head as current block
130
		block.setPrev(null);
131
		bufferHead.setPrev(block);
132
		block.setNext(bufferHead);
133
		bufferHead = block;
134
		// Write last block in list to disk if dirty bit is set
135
		// Last block is also removed
136
		BufferBlock cur = bufferHead;
137
		while (cur.getNext() != null) {
138
			cur = cur.getNext();
139
		}
140
		cur.getPrev().setNext(null);
141
		if (cur.isDirtyBit()) {
142
			writeToDisk(cur);
143
		}
144
	}
145
 
146
	// Reads a new block from disk given an address
147
	private BufferBlock readFromDisk(long address) {
148
		diskReads++;
149
		byte[] data = new byte[blockSize];
150
		long offset = address / blockSize;
151
		offset = offset * blockSize;
152
		try {
153
			file.seek(offset);
154
			file.read(data);
155
		} catch (IOException e) {
156
			e.printStackTrace();
157
		}
158
 
159
		// Pass read block into a new block
160
		BufferBlock newBlock = new BufferBlock(blockSize);
161
		newBlock.setBytes(data, 0, blockSize);
162
		newBlock.setStartAddress(offset);
163
 
164
		return newBlock;
165
	}
166
 
167
	// Writes the specified block to disk
168
	private void writeToDisk(BufferBlock block) {
169
		diskWrites++;
170
		byte[] data = new byte[blockSize];
171
		block.getBytes(data, 0, blockSize);
172
		try {
173
			file.seek(block.getStartAddress());
174
			file.write(data);
175
		} catch (IOException e) {
176
			e.printStackTrace();
177
		}
178
	}
179
 
180
	// Flush the buffer by writing all blocks in buffer to disk
181
	public void flushBuffer() {
182
		BufferBlock cur = bufferHead;
183
		while (cur != null) {
184
			if (cur.isDirtyBit()) {
185
				writeToDisk(cur);
186
			}
187
			cur = cur.getNext();
188
		}
189
 
190
		try {
191
			file.close();
192
		} catch (IOException e) {
193
			e.printStackTrace();
194
		}
195
	}
196
 
197
	// Write stats to stat file
198
	public void writeStats(long time) {
199
		try {
200
			BufferedWriter out = new BufferedWriter(new FileWriter(statFile, true));
201
			StringBuilder str = new StringBuilder();
202
			str.append("Datafile: " + dataFile + " | ");
203
			str.append("Cache Hits: " + cacheHit + " | ");
204
			str.append("Cache Misses: " + cacheMiss + " | ");
205
			str.append("Disk Reads: " + diskReads + " | ");
206
			str.append("Disk Writes: " + diskWrites + " | ");
207
			str.append("Time to Sort: " + time + "\n");
208
			out.write(str.toString());
209
			out.close();
210
		} catch (IOException e) {
211
			e.printStackTrace();
212
		}
213
	}
214
}