Пример #1
0
 private void openHeadLogFile() throws ChangelogException {
   final LogFile<K, V> head =
       LogFile.newAppendableLogFile(new File(logPath, HEAD_LOG_FILE_NAME), recordParser);
   final Record<K, V> newestRecord = head.getNewestRecord();
   lastAppendedKey = newestRecord != null ? newestRecord.getKey() : null;
   logFiles.put(recordParser.getMaxKey(), head);
 }
Пример #2
0
  /**
   * Add the provided record at the end of this log.
   *
   * <p>The record must have a key strictly higher than the key of the last record added. If it is
   * not the case, the record is not appended and the method returns immediately.
   *
   * <p>In order to ensure that record is written out of buffers and persisted to file system, it is
   * necessary to explicitely call the {@code syncToFileSystem()} method.
   *
   * @param record The record to add.
   * @throws ChangelogException If an error occurs while adding the record to the log.
   */
  public void append(final Record<K, V> record) throws ChangelogException {
    // If this exclusive lock happens to be a bottleneck :
    // 1. use a shared lock for appending the record first
    // 2. switch to an exclusive lock only if rotation is needed
    // See http://sources.forgerock.org/cru/CR-3548#c27521 for full detail
    exclusiveLock.lock();
    try {
      if (isClosed) {
        return;
      }
      if (recordIsBreakingKeyOrdering(record)) {
        logger.info(
            LocalizableMessage.raw(
                "Rejecting append to log '%s' for record: [%s], last key appended: [%s]",
                logPath.getPath(), record, lastAppendedKey != null ? lastAppendedKey : "null"));
        return;
      }
      LogFile<K, V> headLogFile = getHeadLogFile();
      if (mustRotate(headLogFile)) {
        logger.trace(
            INFO_CHANGELOG_LOG_FILE_ROTATION.get(logPath.getPath(), headLogFile.getSizeInBytes()));

        rotateHeadLogFile();
        headLogFile = getHeadLogFile();
      }
      headLogFile.append(record);
      lastAppendedKey = record.getKey();
    } finally {
      exclusiveLock.unlock();
    }
  }
Пример #3
0
 /**
  * Find the highest key that corresponds to a record that is the oldest (or first) of a read-only
  * log file and where value mapped from the record is lower or equals to provided limit value.
  *
  * <p>Example<br>
  * Given a log with 3 log files, with Record<Int, String> and Mapper<String, Long> mapping a
  * string to its long value
  *
  * <ul>
  *   <li>1_10.log where oldest record is (key=1, value="50")
  *   <li>11_20.log where oldest record is (key=11, value="150")
  *   <li>head.log where oldest record is (key=25, value="250")
  * </ul>
  *
  * Then
  *
  * <ul>
  *   <li>findBoundaryKeyFromRecord(mapper, 20) => null
  *   <li>findBoundaryKeyFromRecord(mapper, 50) => 1
  *   <li>findBoundaryKeyFromRecord(mapper, 100) => 1
  *   <li>findBoundaryKeyFromRecord(mapper, 150) => 11
  *   <li>findBoundaryKeyFromRecord(mapper, 200) => 11
  *   <li>findBoundaryKeyFromRecord(mapper, 250) => 25
  *   <li>findBoundaryKeyFromRecord(mapper, 300) => 25
  * </ul>
  *
  * @param <V2> Type of the value extracted from the record
  * @param mapper The mapper to extract a value from a record. It is expected that extracted values
  *     are ordered according to an order consistent with this log ordering, i.e. for two records,
  *     if key(R1) > key(R2) then extractedValue(R1) > extractedValue(R2).
  * @param limitValue The limit value to search for
  * @return the key or {@code null} if no key corresponds
  * @throws ChangelogException If a problem occurs
  */
 <V2 extends Comparable<V2>> K findBoundaryKeyFromRecord(
     Record.Mapper<V, V2> mapper, V2 limitValue) throws ChangelogException {
   sharedLock.lock();
   try {
     K key = null;
     for (LogFile<K, V> logFile : logFiles.values()) {
       final Record<K, V> record = logFile.getOldestRecord();
       final V2 oldestValue = mapper.map(record.getValue());
       if (oldestValue.compareTo(limitValue) > 0) {
         return key;
       }
       key = record.getKey();
     }
     return key;
   } finally {
     sharedLock.unlock();
   }
 }
Пример #4
0
 /** Indicates if the provided record has a key that would break the key ordering in the log. */
 private boolean recordIsBreakingKeyOrdering(final Record<K, V> record) {
   return lastAppendedKey != null && record.getKey().compareTo(lastAppendedKey) <= 0;
 }