use of org.fusesource.hawtjournal.api.Journal.WriteBatch 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.WriteBatch 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.WriteBatch 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