use of org.fusesource.hawtjournal.api.Journal.WriteCommand in project hawtjournal by fusesource.
the class DataFileAccessor method readLocation.
Buffer readLocation(Location location) throws IOException {
WriteCommand asyncWrite = journal.getInflightWrites().get(location);
Buffer result = null;
if (asyncWrite != null) {
result = asyncWrite.getData();
} else {
RandomAccessFile raf = getOrCreateRaf(Thread.currentThread(), location.getDataFileId());
Lock threadLock = getOrCreateLock(Thread.currentThread(), location.getDataFileId());
accessorLock.lock();
threadLock.lock();
try {
if (location.getSize() == Location.NOT_SET) {
raf.seek(location.getOffset());
location.setSize(raf.readInt());
location.setType(raf.readByte());
} else {
raf.seek(Journal.HEADER_SIZE + location.getOffset());
}
if (location.isBatchControlRecord()) {
byte[] data = new byte[raf.readInt()];
raf.readFully(data);
result = new Buffer(data, 0, data.length);
} else {
byte[] data = new byte[location.getSize() - Journal.HEADER_SIZE];
raf.readFully(data);
result = new Buffer(data, 0, data.length);
}
} catch (RuntimeException e) {
throw new IOException("Invalid location: " + location + ", : " + e);
} finally {
threadLock.unlock();
accessorLock.unlock();
}
}
if (!location.isDeletedRecord()) {
return result;
} else {
throw new IOException("Deleted location: " + location);
}
}
use of org.fusesource.hawtjournal.api.Journal.WriteCommand in project hawtjournal by fusesource.
the class DataFileAppender method processBatches.
/**
* The async processing loop that writes to the data files and does the
* force calls. Since the file sync() call is the slowest of all the
* operations, this algorithm tries to 'batch' or group together several
* file sync() requests into a single file sync() call. The batching is
* accomplished attaching the same CountDownLatch instance to every force
* request in a group.
*/
private void processBatches() {
try {
boolean last = false;
while (true) {
WriteBatch wb = batchQueue.take();
if (shutdown) {
last = true;
}
if (!wb.isEmpty()) {
boolean newOrRotated = lastAppendDataFile != wb.getDataFile();
if (newOrRotated) {
if (lastAppendRaf != null) {
lastAppendRaf.close();
}
lastAppendDataFile = wb.getDataFile();
lastAppendRaf = lastAppendDataFile.openRandomAccessFile();
}
// perform batch:
Location latest = wb.perform(lastAppendRaf, journal.getReplicationTarget(), journal.isChecksum());
// Adjust journal length and pointers:
journal.addToTotalLength(wb.getSize());
journal.setLastAppendLocation(latest);
// Now that the data is on disk, remove the writes from the in-flight cache and notify listeners.
Collection<WriteCommand> commands = wb.getWrites();
for (WriteCommand current : commands) {
if (!current.isSync()) {
journal.getInflightWrites().remove(current.getLocation());
}
}
if (journal.getListener() != null) {
try {
journal.getListener().synced(commands.toArray(new WriteCommand[commands.size()]));
} catch (Throwable ex) {
warn(ex, ex.getMessage());
}
}
// Signal any waiting threads that the write is on disk.
wb.getLatch().countDown();
}
if (last) {
break;
}
}
} catch (Exception e) {
firstAsyncException.compareAndSet(null, e);
} finally {
try {
if (lastAppendRaf != null) {
lastAppendRaf.close();
}
} catch (Throwable ignore) {
}
shutdownDone.countDown();
}
}
use of org.fusesource.hawtjournal.api.Journal.WriteCommand in project hawtjournal by fusesource.
the class DataFileAccessor method fillLocationDetails.
boolean fillLocationDetails(Location location) throws IOException {
WriteCommand asyncWrite = journal.getInflightWrites().get(location);
if (asyncWrite != null) {
location.setSize(asyncWrite.getLocation().getSize());
location.setType(asyncWrite.getLocation().getType());
return true;
} else {
RandomAccessFile raf = getOrCreateRaf(Thread.currentThread(), location.getDataFileId());
Lock threadLock = getOrCreateLock(Thread.currentThread(), location.getDataFileId());
accessorLock.lock();
threadLock.lock();
try {
if (raf.length() > location.getOffset()) {
raf.seek(location.getOffset());
location.setSize(raf.readInt());
location.setType(raf.readByte());
if (location.getSize() > 0 && location.getType() != Location.NO_RECORD_TYPE) {
return true;
} else {
return false;
}
} else {
return false;
}
} finally {
threadLock.unlock();
accessorLock.unlock();
}
}
}
use of org.fusesource.hawtjournal.api.Journal.WriteCommand in project hawtjournal by fusesource.
the class DataFileAppender method storeItem.
Location storeItem(Buffer data, byte type, boolean sync) throws IOException {
int size = Journal.HEADER_SIZE + data.getLength();
Location location = new Location();
location.setSize(size);
location.setType(type);
WriteCommand write = new WriteCommand(location, data, sync);
WriteBatch batch = enqueue(write);
location.setLatch(batch.getLatch());
if (sync) {
try {
batch.getLatch().await();
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
return location;
}
use of org.fusesource.hawtjournal.api.Journal.WriteCommand in project hawtjournal by fusesource.
the class DataFileAppender method enqueue.
private WriteBatch enqueue(WriteCommand writeRecord) throws IOException {
WriteBatch currentBatch = null;
int spinnings = 0;
int limit = SPIN_RETRIES;
while (true) {
if (shutdown) {
throw new IOException("DataFileAppender Writer Thread Shutdown!");
}
if (firstAsyncException.get() != null) {
throw new IOException(firstAsyncException.get());
}
try {
if (batching.compareAndSet(false, true) && !shutdown) {
try {
if (nextWriteBatch == null) {
DataFile file = journal.getCurrentWriteFile();
boolean canBatch = false;
currentBatch = new WriteBatch(file, file.getLength());
canBatch = currentBatch.canBatch(writeRecord, journal.getMaxWriteBatchSize(), journal.getMaxFileLength());
if (!canBatch) {
file = journal.rotateWriteFile();
currentBatch = new WriteBatch(file, file.getLength());
}
WriteCommand controlRecord = currentBatch.prepareBatch();
currentBatch.appendBatch(writeRecord);
if (!writeRecord.isSync()) {
journal.getInflightWrites().put(controlRecord.getLocation(), controlRecord);
journal.getInflightWrites().put(writeRecord.getLocation(), writeRecord);
nextWriteBatch = currentBatch;
} else {
batchQueue.put(currentBatch);
}
break;
} else {
boolean canBatch = nextWriteBatch.canBatch(writeRecord, journal.getMaxWriteBatchSize(), journal.getMaxFileLength());
if (canBatch && !writeRecord.isSync()) {
nextWriteBatch.appendBatch(writeRecord);
journal.getInflightWrites().put(writeRecord.getLocation(), writeRecord);
currentBatch = nextWriteBatch;
break;
} else if (canBatch && writeRecord.isSync()) {
nextWriteBatch.appendBatch(writeRecord);
batchQueue.put(nextWriteBatch);
currentBatch = nextWriteBatch;
nextWriteBatch = null;
break;
} else {
batchQueue.put(nextWriteBatch);
nextWriteBatch = null;
}
}
} finally {
batching.set(false);
}
} else {
// Spin waiting for new batch ...
if (spinnings <= limit) {
spinnings++;
continue;
} else {
Thread.sleep(SPIN_BACKOFF);
continue;
}
}
} catch (InterruptedException ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
}
return currentBatch;
}
Aggregations