0,0 → 1,214 |
import java.io.BufferedWriter; |
import java.io.FileNotFoundException; |
import java.io.FileWriter; |
import java.io.IOException; |
import java.io.RandomAccessFile; |
|
public class LRUBuffer { |
|
private int blockSize = 0; |
private int recordSize = 0; |
|
private int cacheHit = 0; |
private int cacheMiss = 0; |
private int diskReads = 0; |
private int diskWrites = 0; |
|
private String dataFile; |
private String statFile; |
private int bufferSize; |
|
private BufferBlock bufferHead; |
|
private RandomAccessFile file; |
|
public LRUBuffer(String datafile, String statfile, int size, int blocksize, int recordsize) { |
this.dataFile = datafile; |
this.statFile = statfile; |
this.bufferSize = size; |
this.blockSize = blocksize; |
this.recordSize = recordsize; |
|
// Allocates a new doubly linked list of BufferBlocks |
// The buffer will have at least one block |
bufferHead = new BufferBlock(blockSize); |
BufferBlock cur = bufferHead; |
for (int i = 0; i < size-1; i++) { |
BufferBlock newBlock = new BufferBlock(blockSize); |
cur.setNext(newBlock); |
newBlock.setPrev(cur); |
cur = newBlock; |
} |
|
// Open access to the datafile |
try { |
file = new RandomAccessFile(dataFile, "rw"); |
} catch (FileNotFoundException e) { |
e.printStackTrace(); |
} |
} |
|
// Returns recordSize number of bytes to out from record # pos |
public boolean getBytes(byte[] out, long pos) { |
BufferBlock cur = bufferHead; |
|
// Calculate the address of record |
long address = pos * recordSize; |
|
// Check if address is already in a buffer block |
while (cur != null && cur.getStartAddress() != -1) { |
if (address >= cur.getStartAddress() && address < cur.getStartAddress() + blockSize) { |
// Address is in block, get data |
cacheHit++; |
cur.getBytes(out, (int)address % blockSize, recordSize); |
// Bring current block to front of list |
bringToFront(cur); |
return true; |
} |
cur = cur.getNext(); |
} |
|
// Address is not in buffer, read new block from disk |
cacheMiss++; |
BufferBlock newBlock = readFromDisk(address); |
// Get requested bytes from block |
newBlock.getBytes(out, (int)address % blockSize, recordSize); |
insertToFront(newBlock); |
return false; |
} |
|
// Puts recordSize number of bytes from in to record # pos |
public boolean putBytes(byte[] in, long pos) { |
BufferBlock cur = bufferHead; |
|
// Calculate the address of record |
long address = pos * recordSize; |
|
// Check if address is already in a buffer block |
while (cur != null && cur.getStartAddress() != -1) { |
if (address >= cur.getStartAddress() && address < cur.getStartAddress() + blockSize) { |
// Address is in block, put data |
cacheHit++; |
cur.setBytes(in, (int)address % blockSize, recordSize); |
cur.setDirtyBit(true); |
// Bring current block to front of list |
bringToFront(cur); |
return true; |
} |
cur = cur.getNext(); |
} |
|
// Address is not in buffer, read new block from disk |
cacheMiss++; |
BufferBlock newBlock = readFromDisk(address); |
// Put passed bytes into block |
newBlock.setBytes(in, (int)address % blockSize, recordSize); |
newBlock.setDirtyBit(true); |
insertToFront(newBlock); |
return false; |
} |
|
// Brings a block currently in the list to the front of the list |
private void bringToFront(BufferBlock block) { |
// If block is already in front, return |
if (block == bufferHead) |
return; |
|
if (block.getPrev() != null) |
block.getPrev().setNext(block.getNext()); |
if (block.getNext() != null) |
block.getNext().setPrev(block.getPrev()); |
block.setPrev(null); |
bufferHead.setPrev(block); |
block.setNext(bufferHead); |
bufferHead = block; |
} |
|
// Inserts a new block into the front of the list |
private void insertToFront(BufferBlock block) { |
// Set head as current block |
block.setPrev(null); |
bufferHead.setPrev(block); |
block.setNext(bufferHead); |
bufferHead = block; |
// Write last block in list to disk if dirty bit is set |
// Last block is also removed |
BufferBlock cur = bufferHead; |
while (cur.getNext() != null) { |
cur = cur.getNext(); |
} |
cur.getPrev().setNext(null); |
if (cur.isDirtyBit()) { |
writeToDisk(cur); |
} |
} |
|
// Reads a new block from disk given an address |
private BufferBlock readFromDisk(long address) { |
diskReads++; |
byte[] data = new byte[blockSize]; |
long offset = address / blockSize; |
offset = offset * blockSize; |
try { |
file.seek(offset); |
file.read(data); |
} catch (IOException e) { |
e.printStackTrace(); |
} |
|
// Pass read block into a new block |
BufferBlock newBlock = new BufferBlock(blockSize); |
newBlock.setBytes(data, 0, blockSize); |
newBlock.setStartAddress(offset); |
|
return newBlock; |
} |
|
// Writes the specified block to disk |
private void writeToDisk(BufferBlock block) { |
diskWrites++; |
byte[] data = new byte[blockSize]; |
block.getBytes(data, 0, blockSize); |
try { |
file.seek(block.getStartAddress()); |
file.write(data); |
} catch (IOException e) { |
e.printStackTrace(); |
} |
} |
|
// Flush the buffer by writing all blocks in buffer to disk |
public void flushBuffer() { |
BufferBlock cur = bufferHead; |
while (cur != null) { |
if (cur.isDirtyBit()) { |
writeToDisk(cur); |
} |
cur = cur.getNext(); |
} |
|
try { |
file.close(); |
} catch (IOException e) { |
e.printStackTrace(); |
} |
} |
|
// Write stats to stat file |
public void writeStats(long time) { |
try { |
BufferedWriter out = new BufferedWriter(new FileWriter(statFile, true)); |
StringBuilder str = new StringBuilder(); |
str.append("Datafile: " + dataFile + " | "); |
str.append("Cache Hits: " + cacheHit + " | "); |
str.append("Cache Misses: " + cacheMiss + " | "); |
str.append("Disk Reads: " + diskReads + " | "); |
str.append("Disk Writes: " + diskWrites + " | "); |
str.append("Time to Sort: " + time + "\n"); |
out.write(str.toString()); |
out.close(); |
} catch (IOException e) { |
e.printStackTrace(); |
} |
} |
} |