/** Write data into the database. */
  private void generateData(
      Environment master, int numTxns, Durability durability, boolean doCommit) {

    /* Write some data. */
    DatabaseEntry key = new DatabaseEntry();
    byte[] dataPadding = new byte[1000];
    DatabaseEntry data = new DatabaseEntry(dataPadding);

    TransactionConfig txnConfig = new TransactionConfig();
    txnConfig.setDurability(durability);

    for (int i = 0; i < numTxns; i++) {
      final Transaction txn = master.beginTransaction(null, txnConfig);
      //            long keyPrefix = i << 10;
      //            LongBinding.longToEntry(keyPrefix + i, key);
      LongBinding.longToEntry(i, key);
      db.put(txn, key, data);

      if (doCommit) {
        txn.commit();
      } else {
        txn.abort();
      }
    }
  }
Beispiel #2
0
 private void attemptAbort(Transaction transaction) {
   try {
     if (transaction != null) transaction.abort();
   } catch (Exception e) {
     logger.error("Abort failed!", e);
   }
 }
 @Override
 public synchronized void abort() {
   try {
     closeOpenedCursors();
     dbTransaction.abort();
     getPersistenceManager().unregisterTransaction(this);
     super.abort();
   } catch (DatabaseException e) {
     throw getPersistenceManager().convertDatabaseException(e);
   }
 }
Beispiel #4
0
 /** {@inheritDoc} */
 public void abort() {
   try {
     if (xid != null) {
       env.rollback(xid);
     } else {
       txn.abort();
     }
   } catch (DatabaseException e) {
     throw JeEnvironment.convertException(e, false);
   } catch (XAException e) {
     throw JeEnvironment.convertException(e, false);
   }
 }
Beispiel #5
0
  public List<WebURL> get(int max) throws DatabaseException {
    synchronized (mutex) {
      int matches = 0;
      List<WebURL> results = new ArrayList<WebURL>(max);

      Cursor cursor = null;
      OperationStatus result;
      DatabaseEntry key = new DatabaseEntry();
      DatabaseEntry value = new DatabaseEntry();
      Transaction txn;
      if (resumable) {
        txn = env.beginTransaction(null, null);
      } else {
        txn = null;
      }
      try {
        cursor = urlsDB.openCursor(txn, null);
        result = cursor.getFirst(key, value, null);

        while (matches < max && result == OperationStatus.SUCCESS) {
          if (value.getData().length > 0) {
            results.add(webURLBinding.entryToObject(value));
            matches++;
          }
          result = cursor.getNext(key, value, null);
        }
      } catch (DatabaseException e) {
        if (txn != null) {
          txn.abort();
          txn = null;
        }
        throw e;
      } finally {
        if (cursor != null) {
          cursor.close();
        }
        if (txn != null) {
          txn.commit();
        }
      }
      return results;
    }
  }
Beispiel #6
0
  public void delete(int count) throws DatabaseException {
    synchronized (mutex) {
      int matches = 0;

      Cursor cursor = null;
      OperationStatus result;
      DatabaseEntry key = new DatabaseEntry();
      DatabaseEntry value = new DatabaseEntry();
      Transaction txn;
      if (resumable) {
        txn = env.beginTransaction(null, null);
      } else {
        txn = null;
      }
      try {
        cursor = urlsDB.openCursor(txn, null);
        result = cursor.getFirst(key, value, null);

        while (matches < count && result == OperationStatus.SUCCESS) {
          cursor.delete();
          matches++;
          result = cursor.getNext(key, value, null);
        }
      } catch (DatabaseException e) {
        if (txn != null) {
          txn.abort();
          txn = null;
        }
        throw e;
      } finally {
        if (cursor != null) {
          cursor.close();
        }
        if (txn != null) {
          txn.commit();
        }
      }
    }
  }
  /*
   * See SR11455 for details.
   *
   * This test is checking that the maxTxnId gets recovered properly during
   * recovery.  The SR has to do with the INFileReader not including
   * DupCountLN_TX and DelDupLN_TX's in its txnIdTrackingMap.  When these
   * were not included, it was possible for a transaction to consist solely
   * of DupCountLN_TX/DelDupLN_TX pairs.  The "deleteData" transaction below
   * does just this.  If no checkpoint occurred following such a transaction,
   * then the correct current txnid would not be written to the log and
   * determining this value during recovery would be left up to the
   * INFileReader.  However, without reading the DupCountLN_TX/DelDupLN_TX
   * records, it would not recover the correct value.
   *
   * We take the poor man's way out of creating this situation by just
   * manually asserting the txn id is correct post-recovery.  The txnid of 12
   * was determined by looking through logs before and after the fix.
   */
  public void testSR11455() throws Throwable {

    createEnvAndDbs(1 << 20, true, 1);
    int numRecs = 1;
    int nDups = 3;

    try {
      /* Set up an repository of expected data. */
      Map<TestData, Set<TestData>> expectedData = new HashMap<TestData, Set<TestData>>();

      /* Insert all the data. */
      Transaction txn = env.beginTransaction(null, null);
      insertData(txn, 0, numRecs - 1, expectedData, nDups, true, 1);
      txn.commit();

      txn = env.beginTransaction(null, null);
      /* Delete all the even records. */
      deleteData(txn, expectedData, false, false, 1);
      txn.abort();
      closeEnv();

      /* Open it again, which will run recovery. */
      EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig();
      recoveryConfig.setTransactional(true);
      recoveryConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
      recoveryConfig.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
      env = new Environment(envHome, recoveryConfig);

      txn = env.beginTransaction(null, null);
      assertEquals(6, txn.getId());
      txn.commit();
      env.close();

    } catch (Throwable t) {
      t.printStackTrace();
      throw t;
    }
  }
 @Override
 public synchronized boolean trim(Long instance) {
   if (instance == 0) {
     return true;
   } // fast track
   Transaction t = null;
   if (db.getConfig().getTransactional()) {
     t = env.beginTransaction(null, null);
   }
   Cursor cursor = db.openCursor(t, null);
   boolean dirty = false;
   try {
     while (cursor.getNext(key, data, LockMode.READ_UNCOMMITTED) == OperationStatus.SUCCESS) {
       Long i = keyBinding.entryToObject(key);
       if (i < instance && cursor.delete() != OperationStatus.SUCCESS) {
         logger.error("Error deleting instance " + i + " from DB!");
         dirty = true;
       }
     }
   } finally {
     cursor.close();
     if (!dirty) {
       if (t != null) {
         t.commit();
       }
     } else {
       if (t != null) {
         t.abort();
       }
       return false;
     }
   }
   putDecision(-1L, new Decision(0, instance, 0, null));
   logger.debug("DB deltete up to instance " + instance);
   return true;
 }
Beispiel #9
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());
        }
      }
    }
  }
Beispiel #10
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;
  }
Beispiel #11
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();
    }
  }