All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sirix.cache.TransactionIntentLog Maven / Gradle / Ivy

Go to download

SirixDB is a hybrid on-disk and in-memory document oriented, versioned database system. It has a lightweight buffer manager, stores everything in a huge persistent and durable tree and allows efficient reconstruction of every revision. Furthermore, SirixDB implements change tracking, diffing and supports time travel queries.

There is a newer version: 0.11.0
Show newest version
package org.sirix.cache;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.sirix.api.PageReadOnlyTrx;
import org.sirix.index.IndexType;
import org.sirix.page.*;
import org.sirix.settings.Constants;

import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.*;

/**
 * The transaction intent log, used for logging everything a write transaction changes.
 *
 * @author Johannes Lichtenberger mail
 */
public final class TransactionIntentLog implements AutoCloseable {

  /**
   * The collection to hold the maps.
   */
  private final Map map;

  /**
   * Maps in-memory key to persistent key and vice versa.
   */
  private final Map mapToPersistentLogKey;

  /**
   * The reference to the second cache.
   */
  private final PersistentFileCache secondCache;

  /**
   * The log key.
   */
  private int logKey;

  /**
   * Creates a new transaction intent log.
   *
   * @param secondCache         the reference to the second {@link Cache} where the data is stored when it
   *                            gets removed from the first one.
   * @param maxInMemoryCapacity the maximum size of the in-memory map
   */
  public TransactionIntentLog(final PersistentFileCache secondCache, final int maxInMemoryCapacity) {
    // Assertion instead of checkNotNull(...).
    assert secondCache != null;
    logKey = 0;
    this.secondCache = secondCache;
    mapToPersistentLogKey = new HashMap<>(maxInMemoryCapacity >> 1);
    map = new LinkedHashMap<>(maxInMemoryCapacity >> 1) {
      private static final long serialVersionUID = 1;

      @Override
      protected boolean removeEldestEntry(final Map.@Nullable Entry eldest) {
        if (size() > maxInMemoryCapacity) {
          int i = 0;
          final var iter = map.entrySet().iterator();
          final int size = size();
          while (iter.hasNext() && i < (size / 2)) {
            final Map.Entry entry = iter.next();

            if (isImportant(entry))
              continue;

            i++;
            final PageReference key = entry.getKey();
            assert key.getLogKey() != Constants.NULL_ID_INT;
            PageContainer value = entry.getValue();

            if (value != null) {
              iter.remove();
              TransactionIntentLog.this.secondCache.put(key, value);
              //noinspection UnusedAssignment
              value = null;
              mapToPersistentLogKey.put(key.getLogKey(), key.getPersistentLogKey());
            }
          }
        }
        return false;
      }

      private boolean isImportant(Map.Entry eldest) {
        final var page = eldest.getValue().getComplete();
        if (page instanceof RevisionRootPage || page instanceof NamePage || page instanceof CASPage
            || page instanceof PathPage || page instanceof PathSummaryPage || page instanceof UberPage) {
          return true;
        } else if (page instanceof UnorderedKeyValuePage) {
          var dataPage = (UnorderedKeyValuePage) page;
          return dataPage.getIndexType() != IndexType.DOCUMENT;
        }
        return false;
      }
    };
  }

  /**
   * Retrieves an entry from the cache.
* * @param key the key whose associated value is to be returned. * @return the value associated to this key, or {@code null} if no value with this key exists in the * cache */ public PageContainer get(final PageReference key, final PageReadOnlyTrx pageRtx) { PageContainer value = map.get(key); if (value == null) { if (key.getLogKey() != Constants.NULL_ID_INT) { final Long persistentKey = mapToPersistentLogKey.get(key.getLogKey()); if (persistentKey != null) key.setPersistentLogKey(persistentKey); } value = secondCache.get(key, pageRtx); if (value != null && !PageContainer.emptyInstance().equals(value)) { mapToPersistentLogKey.remove(key.getLogKey()); key.setPersistentLogKey(Constants.NULL_ID_LONG); //key.setPage(value.getModified()); put(key, value); } } return value; } /** * Adds an entry to this cache. If the cache is full, the LRU (least recently used) entry is * dropped. * * @param key the key with which the specified value is to be associated * @param value a value to be associated with the specified key */ public void put(final PageReference key, final PageContainer value) { map.remove(key); key.setKey(Constants.NULL_ID_LONG); key.setLogKey(logKey++); key.setPersistentLogKey(Constants.NULL_ID_LONG); map.put(key, value); } /** * Removes an entry from this cache. * * @param key the key with which the specified value is to be associated */ public void remove(final PageReference key) { map.remove(key); mapToPersistentLogKey.remove(key.getLogKey()); } /** * Clears the cache. */ public void clear() { logKey = 0; map.clear(); } /** * Returns the number of used entries in the cache. * * @return the number of entries currently in the cache. */ public int usedEntries() { return map.size(); } /** * Returns a {@code Collection} that contains a copy of all cache entries. * * @return a {@code Collection} with a copy of the cache content */ public Collection> getAll() { return new ArrayList<>(map.entrySet()); } // @Override // public String toString() { // return MoreObjects.toStringHelper(this).add("First Cache", mMap).add("Second Cache", mSecondCache).toString(); // } /** * Get a view of the underlying map. * * @return an unmodifiable view of all entries in the cache */ public Map getMap() { return Collections.unmodifiableMap(map); } /** * Truncate the log. * * @return this log instance */ public TransactionIntentLog truncate() { secondCache.close(); mapToPersistentLogKey.clear(); map.clear(); return this; } @Override public void close() { map.clear(); secondCache.close(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy