/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Nov 17, 2006 */ package com.bigdata.btree; import com.bigdata.cache.IHardReferenceQueue; /** * Hard reference cache eviction listener writes a dirty node or leaf onto the * persistence store. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> */ public class DefaultEvictionListener implements IEvictionListener { @Override public void evicted(final IHardReferenceQueue<PO> cache, final PO ref) { final AbstractNode<?> node = (AbstractNode<?>) ref; /* * Decrement the reference counter. When it reaches zero (0) we will * evict the node or leaf iff it is dirty. * * Note: The reference counts and the #of distinct nodes or leaves on * the writeRetentionQueue are not exact for a read-only B+Tree because * neither synchronization nor atomic counters are used to track that * information. */ if (--node.referenceCount > 0) { return; } // final AbstractBTree btree = node.btree; // // final BTreeCounters counters = btree.getBtreeCounters(); // // counters.queueEvict.incrementAndGet(); // // if (--node.referenceCount > 0) { // // return; // // } // // counters.queueEvictNoRef.incrementAndGet(); doEviction(node); } private void doEviction(final AbstractNode<?> node) { final AbstractBTree btree = node.btree; if (btree.error != null) { /** * This occurs if an error was detected against a mutable view of * the index (the unisolated index view) and the caller has not * discarded the index and caused it to be reloaded from the most * recent checkpoint. * * @see <a href="http://trac.blazegraph.com/ticket/1005"> Invalidate * BTree objects if error occurs during eviction </a> */ throw new IllegalStateException(AbstractBTree.ERROR_ERROR_STATE, btree.error); } try { // Note: This assert can be violated for a read-only B+Tree since // there is less synchronization. assert btree.isReadOnly() || btree.ndistinctOnWriteRetentionQueue > 0; btree.ndistinctOnWriteRetentionQueue--; if (node.deleted) { /* * Deleted nodes are ignored as they are evicted from the queue. */ return; } // this does not permit transient nodes to be coded. if (node.dirty && btree.store != null) { // // this causes transient nodes to be coded on eviction. // if (node.dirty) { // counters.queueEvictDirty.incrementAndGet(); if (node.isLeaf()) { /* * A leaf is written out directly. */ btree.writeNodeOrLeaf(node); } else { /* * A non-leaf node must be written out using a post-order * traversal so that all dirty children are written through * before the dirty parent. This is required in order to * assign persistent identifiers to the dirty children. */ btree.writeNodeRecursive(node); } // is a coded data record. assert node.isCoded(); // no longer dirty. assert !node.dirty; if (btree.store != null) { // object is persistent (has assigned addr). assert node.identity != PO.NULL; } } // isDirty // This does not insert into the cache. That is handled by writeNodeOrLeaf. // if (btree.globalLRU != null) { // // /* // * Add the INodeData or ILeafData object to the global LRU, NOT the // * Node or Leaf. // * // * Note: The global LRU touch only occurs on eviction from the write // * retention queue. This is nice because it limits the touches on // * the global LRU, which could otherwise be a hot spot. We do a // * touch whether or not the node was persisted since we are likely // * to return to the node in either case. // */ // // final IAbstractNodeData delegate = node.getDelegate(); // // assert delegate != null : node.toString(); // // assert delegate.isCoded() : node.toString(); // // btree.globalLRU.add(delegate); // // } } catch (Throwable e) { if (!btree.readOnly) { /** * If the btree is mutable and an eviction fails, then the index * MUST be discarded. * * @see <a href="http://trac.blazegraph.com/ticket/1005"> * Invalidate BTree objects if error occurs during eviction * </a> */ btree.error = e; // Throw as Error. throw new EvictionError(e); } // Launder the throwable. if (e instanceof RuntimeException) throw (RuntimeException) e; throw new RuntimeException(e); } } }