Ejemplo n.º 1
0
  /**
   * Opens a cursor for a given database, dup'ing an existing CDB cursor if one is open for the
   * current thread.
   */
  Cursor openCursor(Database db, CursorConfig cursorConfig, boolean writeCursor, Transaction txn)
      throws DatabaseException {

    if (cdbMode) {
      CdbCursors cdbCursors = null;
      WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get();
      if (cdbCursorsMap == null) {
        cdbCursorsMap = new WeakHashMap();
        localCdbCursors.set(cdbCursorsMap);
      } else {
        cdbCursors = (CdbCursors) cdbCursorsMap.get(db);
      }
      if (cdbCursors == null) {
        cdbCursors = new CdbCursors();
        cdbCursorsMap.put(db, cdbCursors);
      }

      /*
       * In CDB mode the cursorConfig specified by the user is ignored
       * and only the writeCursor parameter is honored.  This is the only
       * meaningful cursor attribute for CDB, and here we count on
       * writeCursor flag being set correctly by the caller.
       */
      List cursors;
      CursorConfig cdbConfig;
      if (writeCursor) {
        if (cdbCursors.readCursors.size() > 0) {

          /*
           * Although CDB allows opening a write cursor when a read
           * cursor is open, a self-deadlock will occur if a write is
           * attempted for a record that is read-locked; we should
           * avoid self-deadlocks at all costs
           */
          throw new IllegalStateException("cannot open CDB write cursor when read cursor is open");
        }
        cursors = cdbCursors.writeCursors;
        cdbConfig = new CursorConfig();
        DbCompat.setWriteCursor(cdbConfig, true);
      } else {
        cursors = cdbCursors.readCursors;
        cdbConfig = null;
      }
      Cursor cursor;
      if (cursors.size() > 0) {
        Cursor other = ((Cursor) cursors.get(0));
        cursor = other.dup(false);
      } else {
        cursor = db.openCursor(null, cdbConfig);
      }
      cursors.add(cursor);
      return cursor;
    } else {
      return db.openCursor(txn, cursorConfig);
    }
  }
Ejemplo n.º 2
0
  /**
   * Inserts an entity and returns null, or updates it if the primary key already exists and returns
   * the existing entity.
   *
   * <p>If a {@link PrimaryKey#sequence} is used and the primary key field of the given entity is
   * null or zero, this method will assign the next value from the sequence to the primary key field
   * of the given entity.
   *
   * @param txn the transaction used to protect this operation, null to use auto-commit, or null if
   *     the store is non-transactional.
   * @param entity the entity to be inserted or updated.
   * @return the existing entity that was updated, or null if the entity was inserted.
   * @throws DatabaseException the base class for all BDB exceptions.
   */
  public E put(Transaction txn, E entity) throws DatabaseException {

    DatabaseEntry keyEntry = new DatabaseEntry();
    DatabaseEntry dataEntry = new DatabaseEntry();
    assignKey(entity, keyEntry);

    boolean autoCommit = false;
    Environment env = db.getEnvironment();
    if (transactional && txn == null && DbCompat.getThreadTransaction(env) == null) {
      txn = env.beginTransaction(null, getAutoCommitTransactionConfig());
      autoCommit = true;
    }

    CursorConfig cursorConfig = null;
    if (concurrentDB) {
      cursorConfig = new CursorConfig();
      DbCompat.setWriteCursor(cursorConfig, true);
    }
    boolean failed = true;
    Cursor cursor = db.openCursor(txn, cursorConfig);
    LockMode lockMode = locking ? LockMode.RMW : null;
    try {
      while (true) {
        OperationStatus status = cursor.getSearchKey(keyEntry, dataEntry, lockMode);
        if (status == OperationStatus.SUCCESS) {
          E existing = entityBinding.entryToObject(keyEntry, dataEntry);
          entityBinding.objectToData(entity, dataEntry);
          cursor.put(keyEntry, dataEntry);
          failed = false;
          return existing;
        } else {
          entityBinding.objectToData(entity, dataEntry);
          status = cursor.putNoOverwrite(keyEntry, dataEntry);
          if (status != OperationStatus.KEYEXIST) {
            failed = false;
            return null;
          }
        }
      }
    } finally {
      cursor.close();
      if (autoCommit) {
        if (failed) {
          txn.abort();
        } else {
          txn.commit();
        }
      }
    }
  }