/**
  * Closes this store. This will cause all buffers and channels to be closed. Requesting an
  * operation from after this method has been invoked is illegal and an exception will be thrown.
  *
  * <p>This method will start by invoking the {@link #closeStorage} method giving the implementing
  * store way to do anything that it needs to do before the fileChannel is closed.
  */
 public void close() {
   if (fileChannel == null) {
     return;
   }
   closeStorage();
   if (windowPool != null) {
     windowPool.close();
     windowPool = null;
   }
   if ((isReadOnly() && !isBackupSlave()) || idGenerator == null || !storeOk) {
     releaseFileLockAndCloseFileChannel();
     return;
   }
   long highId = idGenerator.getHighId();
   int recordSize = -1;
   if (this instanceof AbstractDynamicStore) {
     recordSize = ((AbstractDynamicStore) this).getBlockSize();
   } else if (this instanceof AbstractStore) {
     recordSize = ((AbstractStore) this).getRecordSize();
   }
   idGenerator.close();
   boolean success = false;
   IOException storedIoe = null;
   // hack for WINBLOWS
   if (!readOnly || backupSlave) {
     for (int i = 0; i < 10; i++) {
       try {
         fileChannel.position(highId * recordSize);
         ByteBuffer buffer = ByteBuffer.wrap(UTF8.encode(getTypeAndVersionDescriptor()));
         fileChannel.write(buffer);
         stringLogger.debug(
             "Closing "
                 + storageFileName
                 + ", truncating at "
                 + fileChannel.position()
                 + " vs file size "
                 + fileChannel.size());
         fileChannel.truncate(fileChannel.position());
         fileChannel.force(false);
         releaseFileLockAndCloseFileChannel();
         success = true;
         break;
       } catch (IOException e) {
         storedIoe = e;
         System.gc();
       }
     }
   } else {
     releaseFileLockAndCloseFileChannel();
     success = true;
   }
   if (!success) {
     throw new UnderlyingStorageException(
         "Unable to close store " + getStorageFileName(), storedIoe);
   }
 }
 /**
  * Acquires a {@link PersistenceWindow} for <CODE>position</CODE> and operation <CODE>type</CODE>.
  * Window must be released after operation has been performed via {@link
  * #releaseWindow(PersistenceWindow)}.
  *
  * @param position The record position
  * @param type The operation type
  * @return a persistence window encapsulating the record
  */
 protected PersistenceWindow acquireWindow(long position, OperationType type) {
   if (!isInRecoveryMode() && (position > getHighId() || !storeOk)) {
     throw new InvalidRecordException(
         "Position["
             + position
             + "] requested for high id["
             + getHighId()
             + "], store is ok["
             + storeOk
             + "] recovery["
             + isInRecoveryMode()
             + "]",
         causeOfStoreNotOk);
   }
   return windowPool.acquire(position, type);
 }
 public WindowPoolStats getWindowPoolStats() {
   return windowPool.getStats();
 }
 public void flushAll() {
   windowPool.flushAll();
 }
 /**
  * Releases the window and writes the data (async) if the <CODE>window</CODE> was a {@link
  * PersistenceRow}.
  *
  * @param window The window to be released
  */
 protected void releaseWindow(PersistenceWindow window) {
   windowPool.release(window);
 }