TableBackedCache.java :  » Database-DBMS » mckoi » com » mckoi » database » Java Open Source

Java Open Source » Database DBMS » mckoi 
mckoi » com » mckoi » database » TableBackedCache.java
/**
 * com.mckoi.database.TableBackedCache  12 Mar 2003
 *
 * Mckoi SQL Database ( http://www.mckoi.com/database )
 * Copyright (C) 2000, 2001, 2002  Diehl and Associates, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * Version 2 as published by the Free Software Foundation.
 *
 * 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 Version 2 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * Version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Change Log:
 * 
 * 
 */

package com.mckoi.database;

import com.mckoi.util.Cache;
import com.mckoi.util.IntegerVector;

/**
 * A TableBackedCache is a special type of a cache in a DataTableConglomerate
 * that is backed by a table in the database.  The purpose of this object is to
 * provide efficient access to some specific information in a table via a
 * cache.
 * <p>
 * For example, we use this object to provide cached access to the system
 * privilege tables.  The engine often performs identical types of priv
 * queries on the database and it's desirable to cache the access to this
 * table.
 * <p>
 * This class provides the following services;
 * 1) Allows for an instance of this object to be attached to a single
 *    DatabaseConnection
 * 2) Listens for any changes that are committed to the table(s) and flushes the
 *    cache as neccessary.
 * <p>
 * Note that this object is designed to fit into the pure serializable
 * transaction isolation system that Mckoi employs.  This object will provide
 * a view of the table as it was when the transaction started.  When the
 * transaction commits (or rollsback) the view is updated to the most current
 * version.  If a change is committed to the tables this cache is backed by,
 * the cache is only flushed when there are no open transactions on the
 * connection.
 *
 * @author Tobias Downer
 */

abstract class TableBackedCache {

  /**
   * The table that this cache is backed by.
   */
  private TableName backed_by_table;

  /**
   * The list of added rows to the table above when a change is
   * committed.
   */
  private IntegerVector added_list;

  /**
   * The list of removed rows from the table above when a change is
   * committed.
   */
  private IntegerVector removed_list;

  /**
   * Set to true when the backing DatabaseConnection has a transaction open.
   */
  private boolean transaction_active;
  
  /**
   * The listener object.
   */
  private TransactionModificationListener listener;
  
  /**
   * Constructs this object.
   */
  protected TableBackedCache(TableName table) {
    this.backed_by_table = table;

    added_list = new IntegerVector();
    removed_list = new IntegerVector();
  }

  /**
   * Adds new row ids to the given list.
   */
  private void addRowsToList(int[] from, IntegerVector list) {
    if (from != null) {
      for (int i = 0; i < from.length; ++i) {
        list.addInt(from[i]);
      }
    }
  }

  /**
   * Attaches this object to a conglomerate.  This applies the appropriate
   * listeners to the tables.
   */
  final void attachTo(TableDataConglomerate conglomerate) {
//    TableDataConglomerate conglomerate = connection.getConglomerate();
    TableName table_name = backed_by_table;
    listener = new TransactionModificationListener() {
      public void tableChange(TableModificationEvent evt) {
        // Ignore.
      }
      public void tableCommitChange(TableCommitModificationEvent evt) {
        TableName table_name = evt.getTableName();
        if (table_name.equals(backed_by_table)) {
          synchronized (removed_list) {
            addRowsToList(evt.getAddedRows(), added_list);
            addRowsToList(evt.getRemovedRows(), removed_list);
          }
        }
      }
    };
    conglomerate.addTransactionModificationListener(table_name, listener);
  }

  /**
   * Call to detach this object from a TableDataConglomerate.
   */
  final void detatchFrom(TableDataConglomerate conglomerate) {
//    TableDataConglomerate conglomerate = connection.getConglomerate();
    TableName table_name = backed_by_table;
    conglomerate.removeTransactionModificationListener(table_name, listener);
  }

  /**
   * Called from DatabaseConnection to notify this object that a new transaction
   * has been started.  When a transaction has started, any committed changes
   * to the table must NOT be immediately reflected in this cache.  Only
   * when the transaction commits is there a possibility of the cache
   * information being incorrect.
   */
  final void transactionStarted() {
    transaction_active = true;
    internalPurgeCache();
  }

  /**
   * Called from DatabaseConnection to notify that object that a transaction
   * has closed.  When a transaction is closed, information in the cache may
   * be invalidated.  For example, if rows 10 - 50 were delete then any
   * information in the cache that touches this data must be flushed from the
   * cache.
   */
  final void transactionFinished() {
    transaction_active = false;
    internalPurgeCache();
  }

  /**
   * Internal method which copies the 'added' and 'removed' row lists and
   * calls the 'purgeCacheOfInvalidatedEntries' method.
   */
  private void internalPurgeCache() {
    // Make copies of the added_list and removed_list
    IntegerVector add, remove;
    synchronized (removed_list) {
      add = new IntegerVector(added_list);
      remove = new IntegerVector(removed_list);
      // Clear the added and removed list
      added_list.clear();
      removed_list.clear();
    }
    // Make changes to the cache
    purgeCacheOfInvalidatedEntries(add, remove);
  }

  /**
   * This method is called when the transaction starts and finishes and must
   * purge the cache of all invalidated entries.
   * <p>
   * Note that this method must NOT make any queries on the database.  It must
   * only, at the most, purge the cache of invalid entries.  A trivial
   * implementation of this might completely clear the cache of all data if
   * removed_row.size() > 0.
   */
  abstract void purgeCacheOfInvalidatedEntries(
                         IntegerVector added_rows, IntegerVector removed_rows);

}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.