Exemple #1
0
  /**
   * Opens a primary index related via a foreign key (relatedEntity). Related indexes are not opened
   * in the same transaction used by the caller to open a primary or secondary. It is OK to leave
   * the related index open when the caller's transaction aborts. It is only important to open a
   * primary and its secondaries atomically.
   */
  private PrimaryIndex getRelatedIndex(String relatedClsName) throws DatabaseException {

    PrimaryIndex relatedIndex = priIndexMap.get(relatedClsName);
    if (relatedIndex == null) {
      EntityMetadata relatedEntityMeta = checkEntityClass(relatedClsName);
      Class relatedKeyCls;
      String relatedKeyClsName;
      Class relatedCls;
      if (rawAccess) {
        relatedCls = RawObject.class;
        relatedKeyCls = Object.class;
        relatedKeyClsName = null;
      } else {
        try {
          relatedCls = EntityModel.classForName(relatedClsName);
        } catch (ClassNotFoundException e) {
          throw new IllegalArgumentException("Related entity class not found: " + relatedClsName);
        }
        relatedKeyClsName =
            SimpleCatalog.keyClassName(relatedEntityMeta.getPrimaryKey().getClassName());
        relatedKeyCls = SimpleCatalog.keyClassForName(relatedKeyClsName);
      }

      /*
       * Cycles are prevented here by adding primary indexes to the
       * priIndexMap as soon as they are created, before opening related
       * indexes.
       */
      relatedIndex =
          getPrimaryIndex(
              relatedKeyCls, relatedKeyClsName,
              relatedCls, relatedClsName);
    }
    return relatedIndex;
  }
Exemple #2
0
  /**
   * Opens any secondary indexes defined in the given entity metadata that are not already open.
   * This method is called when a new entity subclass is encountered when an instance of that class
   * is stored, and the EntityStore.getSubclassIndex has not been previously called for that class.
   * [#15247]
   */
  synchronized void openSecondaryIndexes(
      Transaction txn, EntityMetadata entityMeta, PrimaryOpenState priOpenState)
      throws DatabaseException {

    String entityClassName = entityMeta.getClassName();
    PrimaryIndex<Object, Object> priIndex = priIndexMap.get(entityClassName);
    assert priIndex != null;
    Class<Object> entityClass = priIndex.getEntityClass();

    for (SecondaryKeyMetadata secKeyMeta : entityMeta.getSecondaryKeys().values()) {
      String keyName = secKeyMeta.getKeyName();
      String secName = makeSecName(entityClassName, keyName);
      SecondaryIndex<Object, Object, Object> secIndex = secIndexMap.get(secName);
      if (secIndex == null) {
        String keyClassName = getSecKeyClass(secKeyMeta);
        /* RawMode: should not require class. */
        Class keyClass = SimpleCatalog.keyClassForName(keyClassName);
        openSecondaryIndex(
            txn,
            priIndex,
            entityClass,
            entityMeta,
            keyClass,
            keyClassName,
            secKeyMeta,
            makeSecName(entityClassName, secKeyMeta.getKeyName()),
            storeConfig.getSecondaryBulkLoad() /*doNotCreate*/,
            priOpenState);
      }
    }
  }
Exemple #3
0
 private String getSecKeyClass(SecondaryKeyMetadata secKeyMeta) {
   String clsName = secKeyMeta.getElementClassName();
   if (clsName == null) {
     clsName = secKeyMeta.getClassName();
   }
   return SimpleCatalog.keyClassName(clsName);
 }
 Class getFieldClass() {
   if (cls == null) {
     try {
       cls = SimpleCatalog.classForName(className);
     } catch (ClassNotFoundException e) {
       throw new IllegalStateException(e);
     }
   }
   return cls;
 }
Exemple #5
0
 private void setBtreeComparator(DatabaseConfig config, String clsName) {
   if (!rawAccess) {
     ClassMetadata meta = model.getClassMetadata(clsName);
     if (meta != null) {
       List<FieldMetadata> compositeKeyFields = meta.getCompositeKeyFields();
       if (compositeKeyFields != null) {
         Class keyClass = SimpleCatalog.keyClassForName(clsName);
         if (Comparable.class.isAssignableFrom(keyClass)) {
           Comparator<Object> cmp =
               new PersistComparator(clsName, compositeKeyFields, getKeyBinding(clsName));
           config.setBtreeComparator(cmp);
         }
       }
     }
   }
 }
/**
 * Read-only catalog used by a PersistComparator to return simple formats plus reconstituted enum
 * formats.
 *
 * @author Mark Hayes
 */
class ComparatorCatalog implements Catalog {

  private final Map<String, Format> formatMap;
  private final Catalog simpleCatalog = SimpleCatalog.getInstance();

  ComparatorCatalog(final Map<String, Format> formatMap) {
    this.formatMap = formatMap;
  }

  public int getInitVersion(final Format format, final boolean forReader) {
    return simpleCatalog.getInitVersion(format, forReader);
  }

  public Format getFormat(final int formatId, final boolean expectStored) {
    return simpleCatalog.getFormat(formatId, expectStored);
  }

  public Format getFormat(final Class cls, final boolean checkEntitySubclassIndexes) {
    return simpleCatalog.getFormat(cls, checkEntitySubclassIndexes);
  }

  public Format getFormat(final String className) {
    if (formatMap != null) {
      final Format f = formatMap.get(className);
      if (f != null) {
        return f;
      }
    }
    return simpleCatalog.getFormat(className);
  }

  public Format createFormat(final String clsName, final Map<String, Format> newFormats) {
    return simpleCatalog.createFormat(clsName, newFormats);
  }

  public Format createFormat(final Class type, final Map<String, Format> newFormats) {
    return simpleCatalog.createFormat(type, newFormats);
  }

  public boolean isRawAccess() {
    return simpleCatalog.isRawAccess();
  }

  public Object convertRawObject(final RawObject o, final IdentityHashMap converted) {
    return simpleCatalog.convertRawObject(o, converted);
  }
}
 Object checkAndConvert(Object o, Format declaredFormat) {
   if (o == null) {
     if (declaredFormat.isPrimitive()) {
       throw new IllegalArgumentException(
           "A primitive type may not be null or missing: " + declaredFormat.getClassName());
     }
   } else if (declaredFormat.isSimple()) {
     if (declaredFormat.isPrimitive()) {
       if (o.getClass() != declaredFormat.getWrapperFormat().getType()) {
         throw new IllegalArgumentException(
             "Raw value class: "
                 + o.getClass().getName()
                 + " must be the wrapper class for a primitive type: "
                 + declaredFormat.getClassName());
       }
     } else {
       if (o.getClass() != declaredFormat.getType()) {
         throw new IllegalArgumentException(
             "Raw value class: "
                 + o.getClass().getName()
                 + " must be the declared class for a simple type: "
                 + declaredFormat.getClassName());
       }
     }
   } else {
     if (o instanceof RawObject) {
       Object o2 = null;
       if (!rawAccess) {
         if (converted != null) {
           o2 = converted.get(o);
         } else {
           converted = new IdentityHashMap();
         }
       }
       if (o2 != null) {
         o = o2;
       } else {
         if (!rawAccess) {
           o = catalog.convertRawObject((RawObject) o, converted);
         }
       }
     } else {
       if (!SimpleCatalog.isSimpleType(o.getClass())) {
         throw new IllegalArgumentException(
             "Raw value class: " + o.getClass().getName() + " must be RawObject a simple type");
       }
     }
     if (rawAccess) {
       checkRawType(catalog, o, declaredFormat);
     } else {
       if (!declaredFormat.getType().isAssignableFrom(o.getClass())) {
         throw new IllegalArgumentException(
             "Raw value class: "
                 + o.getClass().getName()
                 + " is not assignable to type: "
                 + declaredFormat.getClassName());
       }
     }
   }
   return o;
 }
Exemple #8
0
  /**
   * 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;
  }
Exemple #9
0
  private void evolveIndex(Format format, EvolveEvent event, EvolveListener listener)
      throws DatabaseException {

    Class entityClass = format.getType();
    String entityClassName = format.getClassName();
    EntityMetadata meta = model.getEntityMetadata(entityClassName);
    String keyClassName = meta.getPrimaryKey().getClassName();
    keyClassName = SimpleCatalog.keyClassName(keyClassName);
    DatabaseConfig dbConfig = getPrimaryConfig(meta);

    PrimaryIndex<Object, Object> index =
        getPrimaryIndex(Object.class, keyClassName, entityClass, entityClassName);
    Database db = index.getDatabase();

    EntityBinding binding = index.getEntityBinding();
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry data = new DatabaseEntry();

    Cursor readCursor = db.openCursor(null, CursorConfig.READ_UNCOMMITTED);
    try {
      while (readCursor.getNext(key, data, null) == OperationStatus.SUCCESS) {
        if (evolveNeeded(key, data, binding)) {
          Transaction txn = null;
          if (dbConfig.getTransactional()) {
            boolean success = false;
            txn = env.beginTransaction(null, null);
          }
          boolean doCommit = false;
          Cursor writeCursor = null;
          try {
            writeCursor = db.openCursor(txn, null);
            if (writeCursor.getSearchKey(key, data, LockMode.RMW) == OperationStatus.SUCCESS) {
              boolean written = false;
              if (evolveNeeded(key, data, binding)) {
                writeCursor.putCurrent(data);
                written = true;
              }
              if (listener != null) {
                EvolveInternal.updateEvent(event, entityClassName, 1, written ? 1 : 0);
                if (!listener.evolveProgress(event)) {
                  break;
                }
              }
            }
          } finally {
            if (writeCursor != null) {
              writeCursor.close();
            }
            if (txn != null) {
              if (doCommit) {
                txn.commit();
              } else {
                txn.abort();
              }
            }
          }
        }
      }
    } finally {
      readCursor.close();
    }
  }