docs: @Override
      public void keypoint() throws LogClosedException, InternalLogException, LogIncompatibleException
      {
          if (tc.isEntryEnabled())
              Tr.entry(tc, "keypoint", this);
  
          // If this recovery log instance has been marked as incompatible then throw an exception
          // accordingly.
          if (incompatible())
          {
              if (tc.isEntryEnabled())
                  Tr.exit(tc, "keypoint", "LogIncompatibleException");
              throw new LogIncompatibleException();
          }
  
          // If this recovery log instance has experienced a serious internal error then prevent this operation from
          // executing.
          if (failed())
          {
              if (tc.isEntryEnabled())
                  Tr.exit(tc, "keypoint", this);
              throw new InternalLogException(null);
          }
  
          // Check that the log is open.
          if (_logHandle == null)
          {
              if (tc.isEntryEnabled())
                  Tr.exit(tc, "keypoint", "LogClosedException");
              throw new LogClosedException(null);
          }
  
          // Try and obtain the exclusive lock that must be held to perform keypoint processing. If this
          // lock is denied then another thread is performing the required keypoint operation and so
          // this method can return after checking that the other thread sucessfully keypointed.
          boolean obtainedLock = false;
          try
          {
              obtainedLock = _controlLock.attemptExclusiveLock();
          } catch (HoldingExclusiveLockException exc)
          {
              // This thread already holds the exclusive lock. That means that the keypoint operation is already 
              // in progress on this thread. This would occur if the keypoint operation actually triggered a
              // keypoint operation. This should never occur in paractice and would represent a serious internal
              // error.
              FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1353", this);
              if (tc.isDebugEnabled())
                  Tr.debug(tc, "The keypoint operation has triggered a keypoint operation.");
              markFailed(exc); /* @MD19484C */
              if (tc.isEntryEnabled())
                  Tr.exit(tc, "keypoint", "InternalLogException");
              throw new InternalLogException(exc);
          }
  
          if (obtainedLock)
          {
              // This thread has been allocated the exclusive lock. That means that we will perform a 'real' keypoint
              // operation on this thread.
  
              // Inform the underlying log handle that we are about to process a keypoint operation. It can
              // use this opportunity to switch files and re-calculate the amount of avialble free space.
              try
              {
                  _logHandle.keypointStarting();
              } catch (InternalLogException exc)
              {
                  FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1373", this);
  
                  markFailed(exc); /* @MD19484C */
  
                  try
                  {
                      _controlLock.releaseExclusiveLock();
                  } catch (Throwable exc2)
                  {
                      // IGNORE - The recovery log service is failing anyway.
                      FFDCFilter.processException(exc2, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1384", this);
                  }
  
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", exc);
                  throw exc;
              } catch (Throwable exc)
              {
                  FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1392", this);
  
                  markFailed(exc); /* @MD19484C */
  
                  try
                  {
                      _controlLock.releaseExclusiveLock();
                  } catch (Throwable exc2)
                  {
                      // IGNORE - The recovery log service is failing anyway.
                      FFDCFilter.processException(exc2, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1403", this);
                  }
  
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", "InternalLogException");
                  throw new InternalLogException(exc);
              }
  
              // Check that there is sufficient space available in the log
              // to perform this keypoint operation.
  
              if (tc.isDebugEnabled())
              {
                  int targetFreeSpace = _logHandle.getFreeSpace();
                  Tr.debug(tc, "Recovery log contains " + _totalDataSize + " payload bytes");
                  Tr.debug(tc, "Target keypoint file has " + targetFreeSpace + " available free bytes");
                  Tr.debug(tc, "Resize trigger constant is " + TOTAL_DATA_RESIZE_TRIGGER);
                  Tr.debug(tc, "Resize trigger value is " + targetFreeSpace * TOTAL_DATA_RESIZE_TRIGGER + " bytes");
              }
  
              if (_totalDataSize > (_logHandle.getFreeSpace() * TOTAL_DATA_RESIZE_TRIGGER))
              {
                  // There is insufficient space in the underlying file to write all of the log's data
                  // while maintaining the required amount of free space in the log. We must, if possible,
                  // resize it.
  
                  // Determine the target for the log's size, capping it to the maximum size specified by the user.
                  final int logFileHeaderSize; /* @MD19753A */
                  try /* @MD19753A */
                  { /* @MD19753A */
                      logFileHeaderSize = _logHandle.logFileHeader().length();/* @MD19753A */
                  } /* @MD19753A */
                  catch (InternalLogException ile) /* @MD19753A */
                  { /* 3@MD19753A */
                      if (tc.isEventEnabled())
                          Tr.debug(tc, "Could not get log file header length", ile);
  
                      FFDCFilter.processException(ile, "com.ibm.ws.recoverylog.spi.RecoveryLogImpl.keypoint", "1780", this);
  
                      markFailed(ile); /* @MD19753A */
  
                      try /* @MD19753A */
                      { /* @MD19753A */
                          _controlLock.releaseExclusiveLock(); /* @MD19753A */
                      } /* @MD19753A */
                      catch (Throwable exc) /* @MD19753A */
                      { /* @MD19753A */
                          // IGNORE - The recovery log service is failing anyway. 2@MD19753A
                          FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.RecoveryLogImpl.keypoint", "1791", this);
                      } /* @MD19753A */
  
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "keypoint"); /* @MD19753A */
                      throw ile; /* @MD19753A */
                  } /* @MD19753A */
                  catch (LogIncompatibleException lie)
                  {
                      FFDCFilter.processException(lie, "com.ibm.ws.recoverylog.spi.RecoveryLogImpl.keypoint", "1575", this);
  
                      // Unlike some instances of LogIncompatibleException that occur when initially opening a recovery
                      // log, this instance is unlikely to occur unless there is a bug in the code. We check the 
                      // version code when we initially open the log and if its not compatible we clear the state and
                      // stop responding. To get as far as a keypoint before this is detected should not occur. Thats
                      // why we convert this exception into an InternalLogException.
                      markFailed(lie);
  
                      try
                      {
                          _controlLock.releaseExclusiveLock();
                      } catch (Throwable exc)
                      {
                          // No FFDC code needed
                          // IGNORE - The recovery log service is failing anyway.
                      }
  
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "keypoint");
                      throw new InternalLogException(lie);
                  }
  
                  final int targetSize = Math.min((int) (_totalDataSize * TOTAL_DATA_RESIZE_MULTIPLIER), ((_maxLogFileSize * 1024) - logFileHeaderSize)); /* @MD19753C */
  
                  if (targetSize < _totalDataSize)
                  {
                      // The log cannot be resized to accommodate all of its data. Mark it as failed to prevent
                      // further I/O occuring and throw the LogFullException back to the caller. Note that we must
                      // mark it as failed BEFORE releasing the exclsuive lock to ensure that any other threads
                      // that are waiting on the lock will be able to detect the failure when they wake up.
                      LogFullException lfe = new LogFullException(null); /* @MD19484M */
                      markFailed(lfe); /* @MD19484C */
  
                      try
                      {
                          _controlLock.releaseExclusiveLock();
                      } catch (Throwable exc2)
                      {
                          // IGNORE - The recovery log service is failing anyway.
                          FFDCFilter.processException(exc2, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1446", this);
                      }
  
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "keypoint", "LogFullException");
                      throw lfe; /* @MD19484C */
                  }
  
                  // Resize the log to the target size
                  _logHandle.resizeLog(targetSize);
              }
  
              try
              {
                  final Iterator recoverableUnits = _recoverableUnits.values().iterator();
  
                  while (recoverableUnits.hasNext())
                  {
                      final RecoverableUnitImpl recoverableUnit = (RecoverableUnitImpl) recoverableUnits.next();
                      recoverableUnit.writeSections(true);
                  }
  
                  _logHandle.keypoint();
              } catch (Throwable exc)
              {
                  // First try and release the locks. Since the recovery log has suffered a fatal error condition
                  // we ignore any failures that occur here.
                  FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1478", this);
  
                  if (tc.isEventEnabled())
                      Tr.event(tc, "Exception caught performing keypoint", exc);
  
                  markFailed(exc);
  
                  try
                  {
                      _controlLock.releaseExclusiveLock();
                  } catch (Throwable exc2)
                  {
                      // IGNORE - The recovery log service is failing anyway.
                      FFDCFilter.processException(exc2, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1491", this);
                  }
  
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", "InternalLogException");
                  throw new InternalLogException(exc);
              }
  
              // issue warning message if log is filling up
              if (!_logWarningIssued && _totalDataSize > ((_maxLogFileSize * 1024 - _totalDataSize) * LOG_WARNING_FACTOR))
              {
                  if (tc.isEventEnabled())
                      Tr.event(tc, "Logfile is filling up, issuing warning.", _logName);
  
                  _logWarningIssued = true;
                  try {
                      _recoveryAgent.logFileWarning(_logName, _totalDataSize, _maxLogFileSize * 1024);
                  } catch (Throwable t)
                  {
                      // shouldn't happen, swallow to ensure lock released
                      FFDCFilter.processException(t, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1511", this);
                  }
              }
  
              try
              {
                  _controlLock.releaseExclusiveLock();
              } catch (NoExclusiveLockException exc2)
              {
                  // This should not occur as we did get the exclusive lock at the top of the method. If this
                  // does occur all we can do is throw an InternalLogException exception.
                  FFDCFilter.processException(exc2, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1506", this);
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", "InternalLogException");
                  throw new InternalLogException(exc2);
              } catch (Throwable exc)
              {
                  FFDCFilter.processException(exc, "com.ibm.ws.recoverylog.spi.MultiScopeRecoveryLog.keypoint", "1512", this);
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", "InternalLogException");
                  throw new InternalLogException(exc);
              }
          }
          else
          {
              // This thread has not been allocated the exclusive lock. This has occured because some other thread
              // was allocated the exclusive lock, performed a 'real' keypoint and then released the exclusive lock
              // again. This thread has been blocked inside the 'attemptExclusiveLock' call whilst this has
              // been going on and has performed a 'piggyback' keypoint - ie all the real work has already
              // been done for this thread by the 'real' keypoint, so we just exit the method as if we had done
              // the keypoint directly.
  
              // Check that no serious internal error occured during the real keypoint operation. If it did then
              // this "piggybacked" keypoint has logically also failed. This must be reported to
              // the caller just as if it was this thread that encountered the problem.
              if (failed())
              {
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "keypoint", this);
                  throw new InternalLogException(null);
              }
          }
  
          if (tc.isEntryEnabled())
              Tr.exit(tc, "keypoint");
      }