예제 #1
0
파일: Store.java 프로젝트: nologic/nabs
  public synchronized void closeClass(Class entityClass) throws DatabaseException {

    checkOpen();
    String clsName = entityClass.getName();
    EntityMetadata entityMeta = checkEntityClass(clsName);

    PrimaryIndex priIndex = priIndexMap.get(clsName);
    if (priIndex != null) {
      /* Close the secondaries first. */
      DatabaseException firstException = null;
      for (SecondaryKeyMetadata keyMeta : entityMeta.getSecondaryKeys().values()) {

        String secName = makeSecName(clsName, keyMeta.getKeyName());
        SecondaryIndex secIndex = secIndexMap.get(secName);
        if (secIndex != null) {
          Database db = secIndex.getDatabase();
          firstException = closeDb(db, firstException);
          firstException = closeDb(secIndex.getKeysDatabase(), firstException);
          secIndexMap.remove(secName);
          deferredWriteDatabases.remove(db);
        }
      }
      /* Close the primary last. */
      Database db = priIndex.getDatabase();
      firstException = closeDb(db, firstException);
      priIndexMap.remove(clsName);
      deferredWriteDatabases.remove(db);

      /* Throw the first exception encountered. */
      if (firstException != null) {
        throw firstException;
      }
    }
  }
예제 #2
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized void setSecondaryConfig(
     Class entityClass, String keyName, SecondaryConfig config) {
   checkOpen();
   String entityClsName = entityClass.getName();
   EntityMetadata entityMeta = checkEntityClass(entityClsName);
   SecondaryKeyMetadata secKeyMeta = checkSecKey(entityMeta, keyName);
   String keyClassName = getSecKeyClass(secKeyMeta);
   String secName = makeSecName(entityClass.getName(), keyName);
   if (secIndexMap.containsKey(secName)) {
     throw new IllegalStateException("Cannot set config after DB is open");
   }
   SecondaryConfig dbConfig = getSecondaryConfig(secName, entityMeta, keyClassName, secKeyMeta);
   if (config.getSortedDuplicates() != dbConfig.getSortedDuplicates()
       || config.getBtreeComparator() != dbConfig.getBtreeComparator()
       || config.getDuplicateComparator() != null
       || config.getAllowPopulate() != dbConfig.getAllowPopulate()
       || config.getKeyCreator() != dbConfig.getKeyCreator()
       || config.getMultiKeyCreator() != dbConfig.getMultiKeyCreator()
       || config.getForeignKeyNullifier() != dbConfig.getForeignKeyNullifier()
       || config.getForeignMultiKeyNullifier() != dbConfig.getForeignMultiKeyNullifier()
       || config.getForeignKeyDeleteAction() != dbConfig.getForeignKeyDeleteAction()
       || config.getForeignKeyDatabase() != null) {
     throw new IllegalArgumentException(
         "One of these properties was illegally changed: "
             + " SortedDuplicates, BtreeComparator, DuplicateComparator,"
             + " AllowPopulate, KeyCreator, MultiKeyCreator,"
             + " ForeignKeyNullifer, ForeignMultiKeyNullifier,"
             + " ForeignKeyDeleteAction, ForeignKeyDatabase");
   }
   secConfigMap.put(secName, config);
 }
예제 #3
0
파일: Store.java 프로젝트: nologic/nabs
  public EvolveStats evolve(EvolveConfig config) throws DatabaseException {

    checkOpen();
    List<Format> toEvolve = new ArrayList<Format>();
    Set<String> configToEvolve = config.getClassesToEvolve();
    if (configToEvolve.isEmpty()) {
      catalog.getEntityFormats(toEvolve);
    } else {
      for (String name : configToEvolve) {
        Format format = catalog.getFormat(name);
        if (format == null) {
          throw new IllegalArgumentException("Class to evolve is not persistent: " + name);
        }
        if (!format.isEntity()) {
          throw new IllegalArgumentException("Class to evolve is not an entity class: " + name);
        }
        toEvolve.add(format);
      }
    }

    EvolveEvent event = EvolveInternal.newEvent();
    for (Format format : toEvolve) {
      if (format.getEvolveNeeded()) {
        evolveIndex(format, event, config.getEvolveListener());
        format.setEvolveNeeded(false);
        catalog.flush();
      }
    }

    return event.getStats();
  }
예제 #4
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized SecondaryConfig getSecondaryConfig(Class entityClass, String keyName) {
   checkOpen();
   String entityClsName = entityClass.getName();
   EntityMetadata entityMeta = checkEntityClass(entityClsName);
   SecondaryKeyMetadata secKeyMeta = checkSecKey(entityMeta, keyName);
   String keyClassName = getSecKeyClass(secKeyMeta);
   String secName = makeSecName(entityClass.getName(), keyName);
   return (SecondaryConfig)
       getSecondaryConfig(secName, entityMeta, keyClassName, secKeyMeta).cloneConfig();
 }
예제 #5
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized SequenceConfig getSequenceConfig(String name) {
   checkOpen();
   SequenceConfig config = sequenceConfigMap.get(name);
   if (config == null) {
     config = new SequenceConfig();
     config.setInitialValue(1);
     config.setRange(1, Long.MAX_VALUE);
     config.setCacheSize(100);
     config.setAutoCommitNoSync(true);
     config.setAllowCreate(!storeConfig.getReadOnly());
     sequenceConfigMap.put(name, config);
   }
   return config;
 }
예제 #6
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized void setPrimaryConfig(Class entityClass, DatabaseConfig config) {
   checkOpen();
   String clsName = entityClass.getName();
   if (priIndexMap.containsKey(clsName)) {
     throw new IllegalStateException("Cannot set config after DB is open");
   }
   EntityMetadata meta = checkEntityClass(clsName);
   DatabaseConfig dbConfig = getPrimaryConfig(meta);
   if (config.getSortedDuplicates()
       || config.getBtreeComparator() != dbConfig.getBtreeComparator()) {
     throw new IllegalArgumentException(
         "One of these properties was illegally changed: "
             + " SortedDuplicates or BtreeComparator");
   }
   priConfigMap.put(clsName, config);
 }
예제 #7
0
파일: Store.java 프로젝트: nologic/nabs
  public synchronized void truncateClass(Transaction txn, Class entityClass)
      throws DatabaseException {

    checkOpen();

    /* Close primary and secondary databases. */
    closeClass(entityClass);

    String clsName = entityClass.getName();
    EntityMetadata entityMeta = checkEntityClass(clsName);

    /*
     * Truncate the primary first and let any exceptions propogate
     * upwards.  Then truncate each secondary, only throwing the first
     * exception.
     */
    String dbName = storePrefix + clsName;
    boolean primaryExists = true;
    try {
      env.truncateDatabase(txn, dbName, false);
    } catch (DatabaseNotFoundException ignored) {
      primaryExists = false;
    }
    if (primaryExists) {
      DatabaseException firstException = null;
      for (SecondaryKeyMetadata keyMeta : entityMeta.getSecondaryKeys().values()) {
        try {
          env.truncateDatabase(
              txn, storePrefix + makeSecName(clsName, keyMeta.getKeyName()), false);
        } catch (DatabaseNotFoundException ignored) {
          /* Ignore secondaries that do not exist. */
        } catch (DatabaseException e) {
          if (firstException == null) {
            firstException = e;
          }
        }
      }
      if (firstException != null) {
        throw firstException;
      }
    }
  }
예제 #8
0
파일: Store.java 프로젝트: nologic/nabs
  public synchronized Sequence getSequence(String name) throws DatabaseException {

    checkOpen();

    if (storeConfig.getReadOnly()) {
      throw new IllegalStateException("Store is read-only");
    }

    Sequence seq = sequenceMap.get(name);
    if (seq == null) {
      if (sequenceDb == null) {
        String dbName = storePrefix + SEQUENCE_DB;
        DatabaseConfig dbConfig = new DatabaseConfig();
        dbConfig.setTransactional(storeConfig.getTransactional());
        dbConfig.setAllowCreate(true);
        sequenceDb = env.openDatabase(null, dbName, dbConfig);
      }
      DatabaseEntry entry = new DatabaseEntry();
      StringBinding.stringToEntry(name, entry);
      seq = sequenceDb.openSequence(null, entry, getSequenceConfig(name));
      sequenceMap.put(name, seq);
    }
    return seq;
  }
예제 #9
0
파일: Store.java 프로젝트: nologic/nabs
  public synchronized void close() throws DatabaseException {

    checkOpen();
    DatabaseException firstException = null;
    try {
      if (rawAccess) {
        boolean allClosed = catalog.close();
        assert allClosed;
      } else {
        synchronized (catalogPool) {
          Map<String, PersistCatalog> catalogMap = catalogPool.get(env);
          assert catalogMap != null;
          if (catalog.close()) {
            /* Remove when the reference count goes to zero. */
            catalogMap.remove(storeName);
          }
        }
      }
      catalog = null;
    } catch (DatabaseException e) {
      if (firstException == null) {
        firstException = e;
      }
    }
    firstException = closeDb(sequenceDb, firstException);
    for (SecondaryIndex index : secIndexMap.values()) {
      firstException = closeDb(index.getDatabase(), firstException);
      firstException = closeDb(index.getKeysDatabase(), firstException);
    }
    for (PrimaryIndex index : priIndexMap.values()) {
      firstException = closeDb(index.getDatabase(), firstException);
    }
    if (firstException != null) {
      throw firstException;
    }
  }
예제 #10
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized DatabaseConfig getPrimaryConfig(Class entityClass) {
   checkOpen();
   String clsName = entityClass.getName();
   EntityMetadata meta = checkEntityClass(clsName);
   return getPrimaryConfig(meta).cloneConfig();
 }
예제 #11
0
파일: Store.java 프로젝트: nologic/nabs
 public synchronized void setSequenceConfig(String name, SequenceConfig config) {
   checkOpen();
   sequenceConfigMap.put(name, config);
 }
예제 #12
0
파일: Store.java 프로젝트: nologic/nabs
  /**
   * A getSecondaryIndex with extra parameters for opening a raw store. keyClassName is used for
   * consistency checking and should be null for a raw store only.
   */
  public synchronized <SK, PK, E1, E2 extends E1> SecondaryIndex<SK, PK, E2> getSecondaryIndex(
      PrimaryIndex<PK, E1> primaryIndex,
      Class<E2> entityClass,
      String entityClassName,
      Class<SK> keyClass,
      String keyClassName,
      String keyName)
      throws DatabaseException {

    assert (rawAccess && keyClassName == null) || (!rawAccess && keyClassName != null);

    checkOpen();

    EntityMetadata entityMeta = null;
    SecondaryKeyMetadata secKeyMeta = null;

    /* Validate the subclass for a subclass index. */
    if (entityClass != primaryIndex.getEntityClass()) {
      entityMeta = model.getEntityMetadata(entityClassName);
      assert entityMeta != null;
      secKeyMeta = checkSecKey(entityMeta, keyName);
      String subclassName = entityClass.getName();
      String declaringClassName = secKeyMeta.getDeclaringClassName();
      if (!subclassName.equals(declaringClassName)) {
        throw new IllegalArgumentException(
            "Key for subclass "
                + subclassName
                + " is declared in a different class: "
                + makeSecName(declaringClassName, keyName));
      }
    }

    /*
     * Even though the primary is already open, we can't assume the
     * secondary is open because we don't automatically open all
     * secondaries when the primary is read-only.  Use auto-commit (a null
     * transaction) since we're opening only one database.
     */
    String secName = makeSecName(entityClassName, keyName);
    SecondaryIndex<SK, PK, E2> secIndex = secIndexMap.get(secName);
    if (secIndex == null) {
      if (entityMeta == null) {
        entityMeta = model.getEntityMetadata(entityClassName);
        assert entityMeta != null;
      }
      if (secKeyMeta == null) {
        secKeyMeta = checkSecKey(entityMeta, keyName);
      }

      /* Check metadata. */
      if (keyClassName == null) {
        keyClassName = getSecKeyClass(secKeyMeta);
      } else {
        String expectClsName = getSecKeyClass(secKeyMeta);
        if (!keyClassName.equals(expectClsName)) {
          throw new IllegalArgumentException(
              "Wrong secondary key class: " + keyClassName + " Correct class is: " + expectClsName);
        }
      }

      secIndex =
          openSecondaryIndex(
              null,
              primaryIndex,
              entityClass,
              entityMeta,
              keyClass,
              keyClassName,
              secKeyMeta,
              secName,
              false /*doNotCreate*/,
              null /*priOpenState*/);
    }
    return secIndex;
  }
예제 #13
0
파일: Store.java 프로젝트: nologic/nabs
  /**
   * A getPrimaryIndex with extra parameters for opening a raw store. primaryKeyClass and
   * entityClass are used for generic typing; for a raw store, these should always be Object.class
   * and RawObject.class. primaryKeyClassName is used for consistency checking and should be null
   * for a raw store only. entityClassName is used to identify the store and may not be null.
   */
  public synchronized <PK, E> PrimaryIndex<PK, E> getPrimaryIndex(
      Class<PK> primaryKeyClass,
      String primaryKeyClassName,
      Class<E> entityClass,
      String entityClassName)
      throws DatabaseException {

    assert (rawAccess && entityClass == RawObject.class)
        || (!rawAccess && entityClass != RawObject.class);
    assert (rawAccess && primaryKeyClassName == null)
        || (!rawAccess && primaryKeyClassName != null);

    checkOpen();

    PrimaryIndex<PK, E> priIndex = priIndexMap.get(entityClassName);
    if (priIndex == null) {

      /* Check metadata. */
      EntityMetadata entityMeta = checkEntityClass(entityClassName);
      PrimaryKeyMetadata priKeyMeta = entityMeta.getPrimaryKey();
      if (primaryKeyClassName == null) {
        primaryKeyClassName = priKeyMeta.getClassName();
      } else {
        String expectClsName = SimpleCatalog.keyClassName(priKeyMeta.getClassName());
        if (!primaryKeyClassName.equals(expectClsName)) {
          throw new IllegalArgumentException(
              "Wrong primary key class: "
                  + primaryKeyClassName
                  + " Correct class is: "
                  + expectClsName);
        }
      }

      /* Create bindings. */
      PersistEntityBinding entityBinding =
          new PersistEntityBinding(catalog, entityClassName, rawAccess);
      PersistKeyBinding keyBinding = getKeyBinding(primaryKeyClassName);

      /* If not read-only, get the primary key sequence. */
      String seqName = priKeyMeta.getSequenceName();
      if (!storeConfig.getReadOnly() && seqName != null) {
        entityBinding.keyAssigner =
            new PersistKeyAssigner(keyBinding, entityBinding, getSequence(seqName));
      }

      /*
       * Use a single transaction for opening the primary DB and its
       * secondaries.  If opening any secondary fails, abort the
       * transaction and undo the changes to the state of the store.
       * Also support undo if the store is non-transactional.
       */
      Transaction txn = null;
      DatabaseConfig dbConfig = getPrimaryConfig(entityMeta);
      if (dbConfig.getTransactional() && env.getThreadTransaction() == null) {
        txn = env.beginTransaction(null, null);
      }
      PrimaryOpenState priOpenState = new PrimaryOpenState(entityClassName);
      boolean success = false;
      try {

        /* Open the primary database. */
        String dbName = storePrefix + entityClassName;
        Database db = env.openDatabase(txn, dbName, dbConfig);
        priOpenState.addDatabase(db);

        /* Create index object. */
        priIndex = new PrimaryIndex(db, primaryKeyClass, keyBinding, entityClass, entityBinding);

        /* Update index and database maps. */
        priIndexMap.put(entityClassName, priIndex);
        if (DbCompat.getDeferredWrite(dbConfig)) {
          deferredWriteDatabases.put(db, null);
        }

        /* If not read-only, open all associated secondaries. */
        if (!dbConfig.getReadOnly()) {
          openSecondaryIndexes(txn, entityMeta, priOpenState);

          /*
           * To enable foreign key contratints, also open all primary
           * indexes referring to this class via a relatedEntity
           * property in another entity. [#15358]
           */
          Set<String> inverseClassNames = inverseRelatedEntityMap.get(entityClassName);
          if (inverseClassNames != null) {
            for (String relatedClsName : inverseClassNames) {
              getRelatedIndex(relatedClsName);
            }
          }
        }
        success = true;
      } finally {
        if (success) {
          if (txn != null) {
            txn.commit();
          }
        } else {
          if (txn != null) {
            txn.abort();
          } else {
            priOpenState.closeDatabases();
          }
          priOpenState.undoState();
        }
      }
    }
    return priIndex;
  }