void open() {
    if (!running) {
      running = true;
      writer =
          new Thread() {

            public void run() {
              try {
                processQueue();
              } catch (Throwable ex) {
                warn(ex, ex.getMessage());
                try {
                  close();
                } catch (Exception ignored) {
                  warn(ignored, ignored.getMessage());
                }
              }
            }
          };
      writer.setPriority(Thread.MAX_PRIORITY);
      writer.setDaemon(true);
      writer.setName("DataFileAppender Writer Thread");
      writer.start();
    }
  }
 Future<Boolean> sync() throws IOException {
   int spinnings = 0;
   int limit = 100;
   while (true) {
     try {
       if (batching.compareAndSet(false, true)) {
         Future result = null;
         if (nextWriteBatch != null) {
           result = new WriteFuture(nextWriteBatch.latch);
           batchQueue.put(nextWriteBatch);
           nextWriteBatch = null;
         } else {
           result = new WriteFuture(new CountDownLatch(0));
         }
         batching.set(false);
         return result;
       } else {
         // Spin waiting for new batch ...
         if (spinnings <= limit) {
           spinnings++;
           continue;
         } else {
           Thread.sleep(250);
           continue;
         }
       }
     } catch (InterruptedException ex) {
       throw new IllegalStateException(ex.getMessage(), ex);
     }
   }
 }
 void close() throws IOException {
   try {
     if (!shutdown) {
       if (running) {
         shutdown = true;
         while (batching.get() == true) {
           Thread.sleep(250);
         }
         if (nextWriteBatch != null) {
           batchQueue.put(nextWriteBatch);
           nextWriteBatch = null;
         } else {
           batchQueue.put(NULL_BATCH);
         }
       } else {
         shutdownDone.countDown();
       }
     }
     shutdownDone.await();
   } catch (InterruptedException e) {
     throw new InterruptedIOException();
   }
 }
 private WriteBatch enqueue(WriteCommand writeRecord) throws IOException {
   WriteBatch currentBatch = null;
   int spinnings = 0;
   int limit = 100;
   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) {
         if (nextWriteBatch == null) {
           DataFile file = journal.getCurrentWriteFile();
           boolean canBatch = false;
           currentBatch = new WriteBatch(file, file.getLength(), writeRecord);
           canBatch = currentBatch.canBatch(writeRecord);
           if (!canBatch) {
             file = journal.rotateWriteFile();
             currentBatch = new WriteBatch(file, file.getLength(), writeRecord);
           }
           WriteCommand controlRecord = new WriteCommand(new Location(), null, false);
           currentBatch.doFirstBatch(controlRecord, writeRecord);
           if (!writeRecord.sync) {
             inflightWrites.put(controlRecord.location, controlRecord);
             inflightWrites.put(writeRecord.location, writeRecord);
             nextWriteBatch = currentBatch;
             batching.set(false);
           } else {
             batchQueue.put(currentBatch);
             batching.set(false);
           }
           break;
         } else {
           boolean canBatch = nextWriteBatch.canBatch(writeRecord);
           if (canBatch && !writeRecord.sync) {
             nextWriteBatch.doAppendBatch(writeRecord);
             inflightWrites.put(writeRecord.location, writeRecord);
             currentBatch = nextWriteBatch;
             batching.set(false);
             break;
           } else if (canBatch && writeRecord.sync) {
             nextWriteBatch.doAppendBatch(writeRecord);
             batchQueue.put(nextWriteBatch);
             currentBatch = nextWriteBatch;
             nextWriteBatch = null;
             batching.set(false);
             break;
           } else {
             batchQueue.put(nextWriteBatch);
             nextWriteBatch = null;
             batching.set(false);
           }
         }
       } else {
         // Spin waiting for new batch ...
         if (spinnings <= limit) {
           spinnings++;
           continue;
         } else {
           Thread.sleep(250);
           continue;
         }
       }
     } catch (InterruptedException ex) {
       throw new IllegalStateException(ex.getMessage(), ex);
     }
   }
   return currentBatch;
 }