/** Get a locker for a read or cursor operation. */
  private static Locker getReadableLocker(
      Environment env, Locker locker, boolean readCommittedIsolation) throws DatabaseException {

    EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env);

    if (locker == null) {
      Transaction xaTxn = env.getThreadTransaction();
      if (xaTxn != null) {
        return DbInternal.getLocker(xaTxn);
      }
    }

    if (locker == null) {
      /* Non-transactional user operations use ThreadLocker. */
      locker = ThreadLocker.createThreadLocker(envImpl);
    } else {

      /*
       * Use the given locker.  For read-committed, wrap the given
       * transactional locker in a special locker for that isolation
       * level.
       */
      if (readCommittedIsolation) {
        locker = ReadCommittedLocker.createReadCommittedLocker(envImpl, locker);
      }
    }
    return locker;
  }
Ejemplo n.º 2
0
 public static Locker getWritableLocker__wrappee__base(
     Environment env,
     Transaction userTxn,
     boolean dbIsTransactional,
     boolean retainNonTxnLocks,
     TransactionConfig autoCommitConfig)
     throws DatabaseException {
   EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
   boolean envIsTransactional = envImpl.isTransactional();
   if (userTxn == null) {
     Transaction xaLocker = env.getThreadTransaction();
     if (xaLocker != null) {
       return DbInternal.getLocker(xaLocker);
     }
   }
   if (dbIsTransactional && userTxn == null) {
     if (autoCommitConfig == null) {
       autoCommitConfig = DbInternal.getDefaultTxnConfig(env);
     }
     return new AutoTxn(envImpl, autoCommitConfig);
   } else if (userTxn == null) {
     if (retainNonTxnLocks) {
       return new BasicLocker(envImpl);
     } else {
       return new ThreadLocker(envImpl);
     }
   } else {
     if (!envIsTransactional) {
       throw new DatabaseException(
           "A Transaction cannot be used because the"
               + " environment was opened"
               + " non-transactionally");
     }
     if (!dbIsTransactional) {
       throw new DatabaseException(
           "A Transaction cannot be used because the"
               + " database was opened"
               + " non-transactionally");
     }
     Locker locker = DbInternal.getLocker(userTxn);
     if (locker.isReadCommittedIsolation() && !retainNonTxnLocks) {
       return new ReadCommittedLocker(envImpl, locker);
     } else {
       return locker;
     }
   }
 }
Ejemplo n.º 3
0
 private static Locker getReadableLocker__wrappee__base(
     Environment env, Locker locker, boolean retainNonTxnLocks, boolean readCommittedIsolation)
     throws DatabaseException {
   EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
   if (locker == null) {
     Transaction xaTxn = env.getThreadTransaction();
     if (xaTxn != null) {
       return DbInternal.getLocker(xaTxn);
     }
   }
   if (locker == null) {
     if (retainNonTxnLocks) {
       locker = new BasicLocker(envImpl);
     } else {
       locker = new ThreadLocker(envImpl);
     }
   } else {
     if (readCommittedIsolation && !retainNonTxnLocks) {
       locker = new ReadCommittedLocker(envImpl, locker);
     }
   }
   return locker;
 }
  /**
   * Get a locker for a write operation.
   *
   * @param autoTxnIsReplicated is true if this transaction is executed on a rep group master, and
   *     needs to be broadcast. Currently, all application-created transactions are of the type
   *     com.sleepycat.je.txn.Txn, and are replicated if the parent environment is replicated. Auto
   *     Txns are trickier because they may be created for a local write operation, such as log
   *     cleaning.
   * @throws IllegalArgumentException via db/cursor read/write methods.
   */
  public static Locker getWritableLocker(
      Environment env,
      Transaction userTxn,
      boolean isInternalDb,
      boolean dbIsTransactional,
      boolean autoTxnIsReplicated,
      TransactionConfig autoCommitConfig)
      throws DatabaseException {

    EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env);
    boolean envIsTransactional = envImpl.isTransactional();

    if (userTxn == null) {
      Transaction xaLocker = env.getThreadTransaction();
      if (xaLocker != null) {
        return DbInternal.getLocker(xaLocker);
      }
    }

    if (dbIsTransactional && userTxn == null) {

      if (autoCommitConfig == null) {
        autoCommitConfig = DbInternal.getDefaultTxnConfig(env);
      }

      return Txn.createAutoTxn(
          envImpl,
          autoCommitConfig,
          (autoTxnIsReplicated ? ReplicationContext.MASTER : ReplicationContext.NO_REPLICATE));

    } else if (userTxn == null) {
      /* Non-transactional user operations use ThreadLocker. */
      return ThreadLocker.createThreadLocker(envImpl);
    } else {

      /*
       * The user provided a transaction, the environment and the
       * database had better be opened transactionally.
       */
      if (!isInternalDb && !envIsTransactional) {
        throw new IllegalArgumentException(
            "A Transaction cannot be used because the"
                + " environment was opened non-transactionally");
      }
      if (!dbIsTransactional) {
        throw new IllegalArgumentException(
            "A Transaction cannot be used because the"
                + " database was opened non-transactionally");
      }

      /*
       * Use the locker for the given transaction.  For read-comitted,
       * wrap the given transactional locker in a special locker for that
       * isolation level.
       */
      Locker locker = DbInternal.getLocker(userTxn);
      if (locker.isReadCommittedIsolation()) {
        return ReadCommittedLocker.createReadCommittedLocker(envImpl, locker);
      }

      return locker;
    }
  }
Ejemplo n.º 5
0
  public Store(Environment env, String storeName, StoreConfig config, boolean rawAccess)
      throws DatabaseException {

    this.env = env;
    this.storeName = storeName;
    this.rawAccess = rawAccess;

    if (env == null || storeName == null) {
      throw new NullPointerException("env and storeName parameters must not be null");
    }
    if (config != null) {
      model = config.getModel();
      mutations = config.getMutations();
    }
    if (config == null) {
      storeConfig = StoreConfig.DEFAULT;
    } else {
      storeConfig = config.cloneConfig();
    }

    storePrefix = NAME_PREFIX + storeName + NAME_SEPARATOR;
    priIndexMap = new HashMap<String, PrimaryIndex>();
    secIndexMap = new HashMap<String, SecondaryIndex>();
    priConfigMap = new HashMap<String, DatabaseConfig>();
    secConfigMap = new HashMap<String, SecondaryConfig>();
    keyBindingMap = new HashMap<String, PersistKeyBinding>();
    sequenceMap = new HashMap<String, Sequence>();
    sequenceConfigMap = new HashMap<String, SequenceConfig>();
    deferredWriteDatabases = new IdentityHashMap<Database, Object>();

    if (rawAccess) {
      /* Open a read-only catalog that uses the stored model. */
      if (model != null) {
        throw new IllegalArgumentException("A model may not be specified when opening a RawStore");
      }
      DatabaseConfig dbConfig = new DatabaseConfig();
      dbConfig.setReadOnly(true);
      dbConfig.setTransactional(storeConfig.getTransactional());
      catalog =
          new PersistCatalog(
              null,
              env,
              storePrefix,
              storePrefix + CATALOG_DB,
              dbConfig,
              model,
              mutations,
              rawAccess,
              this);
    } else {
      /* Open the shared catalog that uses the current model. */
      synchronized (catalogPool) {
        Map<String, PersistCatalog> catalogMap = catalogPool.get(env);
        if (catalogMap == null) {
          catalogMap = new HashMap<String, PersistCatalog>();
          catalogPool.put(env, catalogMap);
        }
        catalog = catalogMap.get(storeName);
        if (catalog != null) {
          catalog.openExisting();
        } else {
          Transaction txn = null;
          if (storeConfig.getTransactional() && env.getThreadTransaction() == null) {
            txn = env.beginTransaction(null, null);
          }
          boolean success = false;
          try {
            DatabaseConfig dbConfig = new DatabaseConfig();
            dbConfig.setAllowCreate(storeConfig.getAllowCreate());
            dbConfig.setReadOnly(storeConfig.getReadOnly());
            dbConfig.setTransactional(storeConfig.getTransactional());
            catalog =
                new PersistCatalog(
                    txn,
                    env,
                    storePrefix,
                    storePrefix + CATALOG_DB,
                    dbConfig,
                    model,
                    mutations,
                    rawAccess,
                    this);
            catalogMap.put(storeName, catalog);
            success = true;
          } finally {
            if (txn != null) {
              if (success) {
                txn.commit();
              } else {
                txn.abort();
              }
            }
          }
        }
      }
    }

    /* Get the merged mutations from the catalog. */
    mutations = catalog.getMutations();

    /*
     * If there is no model parameter, use the default or stored model
     * obtained from the catalog.
     */
    model = catalog.getResolvedModel();

    /*
     * Give the model a reference to the catalog to fully initialize the
     * model.  Only then may we initialize the Converter mutations, which
     * themselves may call model methods and expect the model to be fully
     * initialized.
     */
    ModelInternal.setCatalog(model, catalog);
    for (Converter converter : mutations.getConverters()) {
      converter.getConversion().initialize(model);
    }

    /*
     * For each existing entity with a relatedEntity reference, create an
     * inverse map (back pointer) from the class named in the relatedEntity
     * to the class containing the secondary key.  This is used to open the
     * class containing the secondary key whenever we open the
     * relatedEntity class, to configure foreign key constraints. Note that
     * we do not need to update this map as new primary indexes are
     * created, because opening the new index will setup the foreign key
     * constraints. [#15358]
     */
    inverseRelatedEntityMap = new HashMap<String, Set<String>>();
    List<Format> entityFormats = new ArrayList<Format>();
    catalog.getEntityFormats(entityFormats);
    for (Format entityFormat : entityFormats) {
      EntityMetadata entityMeta = entityFormat.getEntityMetadata();
      for (SecondaryKeyMetadata secKeyMeta : entityMeta.getSecondaryKeys().values()) {
        String relatedClsName = secKeyMeta.getRelatedEntity();
        if (relatedClsName != null) {
          Set<String> inverseClassNames = inverseRelatedEntityMap.get(relatedClsName);
          if (inverseClassNames == null) {
            inverseClassNames = new HashSet<String>();
            inverseRelatedEntityMap.put(relatedClsName, inverseClassNames);
          }
          inverseClassNames.add(entityMeta.getClassName());
        }
      }
    }
  }
Ejemplo n.º 6
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;
  }