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

thredds.inventory.bdb.MetadataManager Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

There is a newer version: 4.3.22
Show newest version
/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package thredds.inventory.bdb;

import com.sleepycat.je.*;

import java.io.*;
import java.util.*;

import thredds.inventory.MFile;

/**
 * MetadataManager using Berkeley DB Java Edition.
 * Single environment, with multiple databases.
 * All threads share one environment; multiple processes can only have one writer at a time.
 * Each collection is a "database".
 * Each database has a set of key/value pairs.
 * default root dir is ${user.home}/.unidata/bdb
 * default TDS uses {tomcat_home}/content/thredds/cache/collection
 *
 * @author caron
 * @since Aug 20, 2008
 */
public class MetadataManager {
  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MetadataManager.class);
  private static final String UTF8 = "UTF-8";

  private static String root = null;
  private static Environment myEnv = null;
  private static List openDatabases = new ArrayList();
  private static boolean readOnly = false;
  private static boolean debug = false;
  private static boolean debugDelete = false;

  static {
    String home = System.getProperty("user.home");

    if (home == null)
      home = System.getProperty("user.dir");

    if (home == null)
      home = ".";

    root = home + "/.unidata/bdb/";
  }

  static public void setCacheDirectory(String dir) {
    root = dir;
  }

  static private synchronized void setup() throws DatabaseException {
    if (myEnv != null) return; // someone else did it

    EnvironmentConfig myEnvConfig = new EnvironmentConfig();
    myEnvConfig.setReadOnly(false);
    myEnvConfig.setAllowCreate(true);
    myEnvConfig.setSharedCache(true);

    File dir = new File(root);
    if (!dir.exists() && !dir.mkdirs())
      logger.warn("MetadataManager failed to make directory " + root);

    try {
      myEnv = new Environment(dir, myEnvConfig); // LOOK may want to try multiple Environments
      logger.info("MetadataManager opened bdb in directory=" + dir);
      readOnly = false;

     } catch (com.sleepycat.je.EnvironmentLockedException e) {
      // another process has it open: try read-only
      logger.warn("MetadataManager failed to open directory, try read-only");
      readOnly = true;
      myEnvConfig.setReadOnly(true);
      myEnvConfig.setAllowCreate(false);
      myEnv = new Environment(dir, myEnvConfig);
    }
    logger.info("MetadataManager: open bdb at root "+root+" readOnly = " +readOnly);

    /* primary
    DatabaseConfig dbConfig = new DatabaseConfig();
    dbConfig.setAllowCreate(true);
    dbConfig.setDeferredWrite(true);
    database = myEnv.openDatabase(null, "primaryDatabase", dbConfig);

    /* secondary
    SecondaryKeyCreator keyCreator = new SecondaryKeyCreator(new DataBinding());
    SecondaryConfig secConfig = new SecondaryConfig();
    secConfig.setAllowCreate(!readOnly);
    secConfig.setSortedDuplicates(!readOnly);
    secConfig.setKeyCreator(keyCreator);

    secondary = myEnv.openSecondaryDatabase(null, "secDatabase", database, secConfig);  */
  }

  // Close all databases and environment
  // this is called on TDS shutdown and reinit
  static synchronized public void closeAll() {

    List closeDatabases = new ArrayList(openDatabases);
    for (MetadataManager mm : closeDatabases) {
      if (debug) System.out.println("  close database " + mm.collectionName);
      mm.close();
    }
    openDatabases = new ArrayList(); // empty

    if (myEnv != null) {
      try {
        // Finally, close the store and environment.
        myEnv.close();
        myEnv = null;
        logger.info("closed bdb caching");

      } catch (DatabaseException dbe) {
        logger.error("Error closing bdb: ", dbe);
      }
    }
  }

  static public void showEnvStats(Formatter f) {
    if (myEnv == null)
      setup();

    try {
      EnvironmentStats stats = myEnv.getStats(null);
      f.format("EnvironmentStats%n%s%n", stats);

      f.format("%nDatabaseNames%n");
      for (String dbName : myEnv.getDatabaseNames()) {
        f.format(" %s%n", dbName);
      }
    } catch (DatabaseException e) {
      e.printStackTrace();
    }
  }

  static public String getCacheLocation() {
    return root;
  }

  static public void sync() {
    if (myEnv != null)
      myEnv.sync();
  }

  static public List getCollectionNames() {
    if (myEnv == null)
      setup();
    return myEnv.getDatabaseNames();
  }

  static public void deleteCollection(String collectionName) throws Exception {
    // close any open handles
    for (MetadataManager mm : openDatabases) {
      if (mm.collectionName.equals(collectionName)) {
        if (mm.database != null)
          mm.database.close();
      }
    }
    myEnv.removeDatabase(null, collectionName);
  }

  static public void delete(String collectionName, String key) {
    try {
      MetadataManager mm = new MetadataManager(collectionName);
      mm.delete(key);
      mm.close();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  ////////////////////////////////////////////////////

  private String collectionName;
  private Database database;
  //private SecondaryDatabase secondary;
  //private Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
  //private DateFormatter dateFormatter = new DateFormatter();

  public MetadataManager(String collectionName) throws DatabaseException, IOException {
    this.collectionName = collectionName;

    // fail fast
    if (myEnv == null) {
      setup();
    }
  }

  // assumes only one open at a time; could have MetadataManagers share open databases
  private void openDatabase() {
    if (database != null) return;
    DatabaseConfig dbConfig = new DatabaseConfig();
    dbConfig.setReadOnly(readOnly);
    dbConfig.setAllowCreate(!readOnly);
    if (!readOnly)
      dbConfig.setDeferredWrite(true);
    database = myEnv.openDatabase(null, collectionName, dbConfig);
    
    openDatabases.add(this);
  }

  public void put(String key, String value) {
    if (readOnly) return;
    openDatabase();
    try {
      database.put(null, new DatabaseEntry(key.getBytes(UTF8)), new DatabaseEntry(value.getBytes(UTF8)));
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e.getMessage());
    }
  }

  public void put(byte[] key, byte[] value) {
    if (readOnly) return;
    openDatabase();
    database.put(null, new DatabaseEntry(key), new DatabaseEntry(value));
  }

  public void put(String key, byte[] value) {
    if (readOnly) return;
    openDatabase();
    try {
      database.put(null, new DatabaseEntry(key.getBytes(UTF8)), new DatabaseEntry(value));
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e.getMessage());
    }
  }

  public byte[] get(byte[] key) {
    openDatabase();
    DatabaseEntry value = new DatabaseEntry();
    database.get(null, new DatabaseEntry(key), value, LockMode.DEFAULT);
    return value.getData();
  }

  public byte[] getBytes(String key) {
    openDatabase();
    try {
      DatabaseEntry value = new DatabaseEntry();
      database.get(null, new DatabaseEntry(key.getBytes(UTF8)), value, LockMode.DEFAULT);
      return value.getData();
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  public String get(String key) {
    openDatabase();
    try {
      DatabaseEntry value = new DatabaseEntry();
      OperationStatus status = database.get(null, new DatabaseEntry(key.getBytes(UTF8)), value, LockMode.DEFAULT);
      if (status == OperationStatus.SUCCESS)
        return new String(value.getData(), UTF8);
      else
        return null;
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  public void delete(String theKey) {
    if (readOnly) {
      logger.warn("Cant dekete - readOnly mode");
      return;
    }

    openDatabase();
    try {
      DatabaseEntry entry = new DatabaseEntry(theKey.getBytes("UTF-8"));
      database.delete(null, entry);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public void delete(Map current) {
    if (readOnly) {
      logger.warn("Cant dekete - readOnly mode");
      return;
    }
    
    openDatabase();
    List result = new ArrayList();
    Cursor myCursor = null;
    try {
      myCursor = database.openCursor(null, null);
      DatabaseEntry foundKey = new DatabaseEntry();
      DatabaseEntry foundData = new DatabaseEntry();

      int count = 0;
      while (myCursor.getNext(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
        String key = new String(foundKey.getData(), UTF8);
        int pos = key.indexOf('#');
        if (pos > 0) {
          String filename = key.substring(0, pos);
          if (null == current.get(filename)) {
            //System.out.printf("%s not current %n", filename);
            result.add(new DatabaseEntry(foundKey.getData()));
            count++;
          } else {
            //System.out.printf("%s is current%n", filename);
          }
        }
      }

      //System.out.printf("total found to delete = %d%n", count);

      if (debugDelete) {
        for (DatabaseEntry entry : result) {
          OperationStatus status = database.delete(null, entry);
          String key = new String(entry.getData(), UTF8);
          System.out.printf("%s deleted %s%n", status, key);
        }
      }

    } catch (UnsupportedOperationException e) {
      logger.error("Trying to delete " + collectionName, e);

    } catch (UnsupportedEncodingException e) {
      logger.error("Trying to delete " + collectionName, e);

    } finally {
      if (null != myCursor)
        myCursor.close();
    }

  }

  public void close() {
    if (database != null) {
      database.close();
      openDatabases.remove(this);
      database = null;
    }
  }

  public void showStats(Formatter f) {
    openDatabase();
    try {
      DatabaseStats dstats = database.getStats(null);
      f.format("primary stats %n%s%n", dstats);

    } catch (DatabaseException e) {
      e.printStackTrace();
    }
  }

  public List getContent() throws DatabaseException, UnsupportedEncodingException {
    openDatabase();
    List result = new ArrayList();
    Cursor myCursor = null;
    try {
      myCursor = database.openCursor(null, null);
      DatabaseEntry foundKey = new DatabaseEntry();
      DatabaseEntry foundData = new DatabaseEntry();

      //int count = 0;
      while (myCursor.getNext(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
        String key = new String(foundKey.getData(), UTF8);
        String data = new String(foundData.getData(), UTF8);
        result.add(new KeyValue(key, data));
        //System.out.printf("key = %s; data = %s %n", key, data);
        //count++;
      }
      //System.out.printf("count = %d %n", count);
    } finally {
      if (null != myCursor)
        myCursor.close();
    }

    return result;
  }

  public class KeyValue {
    public String key;
    public String value;

    KeyValue(String key, String value) {
      this.key = key;
      this.value = value;
    }
  }

  public static void main(String args[]) throws Exception {
    MetadataManager indexer = new MetadataManager("dummy");
    indexer.showStats(new Formatter(System.out));
    MetadataManager.closeAll();
  }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy