Пример #1
0
  @Test
  public void testCursorPutAndGet() throws Exception {
    k1.putLong(0, 14);
    v1.putLong(0, 15);
    k2.putLong(0, 16);
    v2.putLong(0, 17);

    try (Transaction tx = env.createWriteTransaction()) {
      try (Cursor cursor = db.openCursor(tx)) {
        cursor.put(k1, v1, 0);
        cursor.put(k2, v2, 0);
      }
      tx.commit();
    }

    DirectBuffer k = new DirectBuffer();
    DirectBuffer v = new DirectBuffer();

    try (Transaction tx = env.createReadTransaction()) {
      try (Cursor cursor = db.openCursor(tx)) {
        cursor.position(k, v, GetOp.FIRST);
        assertThat(k.getLong(0), is(14L));
        assertThat(v.getLong(0), is(15L));

        cursor.position(k, v, GetOp.NEXT);
        assertThat(k.getLong(0), is(16L));
        assertThat(v.getLong(0), is(17L));
      }
    }
  }
Пример #2
0
  @Test
  public void testCursorSeekRange() throws Exception {
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);
    k1.putLong(0, 18);
    v1.putLong(0, 19);
    k2.putLong(0, 20);
    v2.putLong(0, 21);

    try (Transaction tx = env.createWriteTransaction()) {
      try (Cursor cursor = db.openCursor(tx)) {
        cursor.put(k1, v1, 0);
        cursor.put(k2, v2, 0);
      }
      tx.commit();
    }

    try (Transaction tx = env.createReadTransaction()) {
      try (Cursor cursor = db.openCursor(tx)) {
        DirectBuffer k = new DirectBuffer(byteBuffer);
        DirectBuffer v = new DirectBuffer();
        k.putLong(0, 10);

        cursor.seekPosition(k, v, SeekOp.RANGE);
        assertThat(k.getLong(0), is(18L));
        assertThat(v.getLong(0), is(19L));

        k.wrap(byteBuffer);
        k.putLong(0, 19);
        cursor.seekPosition(k, v, SeekOp.RANGE);
        assertThat(k.getLong(0), is(20L));
        assertThat(v.getLong(0), is(21L));
      }
    }
  }
Пример #3
0
  public static Database buildtertiary(Database std) {

    try {
      // configure new database instance
      io.deleteFile("tertiarydb");
      DatabaseConfig dbConfig = new DatabaseConfig();
      dbConfig.setType(DatabaseType.HASH);
      dbConfig.setAllowCreate(true);
      dbConfig.setUnsortedDuplicates(true);
      Database tdb = new Database("tertiarydb", null, dbConfig);

      // configure cursors and entries
      Cursor stdCurs = std.openCursor(null, null);
      Cursor tCurs = tdb.openCursor(null, null);
      DatabaseEntry stdKey = new DatabaseEntry();
      DatabaseEntry stdData = new DatabaseEntry();
      DatabaseEntry tKey = new DatabaseEntry();
      DatabaseEntry tData = new DatabaseEntry();

      // extract from linearly constructed database to populate <song>,<users> table, making
      // use of songs grouped by id
      String currUsers = "";
      String prevID = "default";
      boolean firstIter = true;
      while (stdCurs.getNext(stdKey, stdData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
        // get rating data from current row
        String[] currIDUser = (new String(stdKey.getData())).split(",");
        String currID = currIDUser[0].trim();
        String currUser = currIDUser[1].trim();
        String currRating = (new String(stdData.getData()));
        stdKey.setData(null);
        stdData.setData(null);
        if (currID.equals(prevID) || firstIter) {
          // concatenate new username with current string
          currUsers += "(" + currUser + "," + currRating + ")";
        } else if (!firstIter) {
          // insert completed <usernames> into table under key <song id>
          tKey.setData(prevID.getBytes());
          tData.setData(currUsers.substring(0, currUsers.length()).getBytes());
          tCurs.put(tKey, tData);
          tKey.setData(null);
          tData.setData(null);
          // DEBUG:
          // System.out.println(prevID+","+currUsers.substring(0, currUsers.length()-1));
          // start the new <usernames> for the next song (in currID)
          currUsers = "(" + currUser + "," + currRating + ")";
        }
        prevID = currID;
        firstIter = false;
      }
      // repeat iteration for last song
      tKey.setData(prevID.getBytes());
      tData.setData(currUsers.substring(0, currUsers.length()).getBytes());
      tCurs.put(tKey, tData);
      tKey.setData(null);
      tData.setData(null);

      // DEBUG:
      // io.debugread(tdb);
      tCurs.close();

      return tdb;

    } catch (Exception e) {
      System.out.println(" error creating <song>,<users> tertiary table\n");
      System.out.println(e.getMessage());
    }
    return null; // should never happen
  }
Пример #4
0
  /**
   * Returns the next available element in the sequence and changes the sequence value by <code>
   * delta</code>. The value of <code>delta</code> must be greater than zero. If there are enough
   * cached values in the sequence handle then they will be returned. Otherwise the next value will
   * be fetched from the database and incremented (decremented) by enough to cover the <code>delta
   * </code> and the next batch of cached values.
   *
   * <p>This method is synchronized to protect updating of the cached value, since multiple threads
   * may share a single handle. Multiple handles for the same database/key may be used to increase
   * concurrency.
   *
   * <p>The <code>txn</code> handle must be null if the sequence handle was opened with a non-zero
   * cache size.
   *
   * <p>For maximum concurrency, a non-zero cache size should be specified prior to opening the
   * sequence handle, the <code>txn</code> handle should be <code>null</code>, and {@link
   * com.sleepycat.je.SequenceConfig#setAutoCommitNoSync SequenceConfig.setAutoCommitNoSync} should
   * be called to disable log flushes.
   *
   * @param txn For a transactional database, an explicit transaction may be specified, or null may
   *     be specified to use auto-commit. For a non-transactional database, null must be specified.
   * @param delta the amount by which to increment or decrement the sequence
   * @return the next available element in the sequence
   * @throws SequenceOverflowException if the end of the sequence is reached and wrapping is not
   *     configured.
   * @throws SequenceIntegrityException if the sequence record has been deleted.
   * @throws OperationFailureException if one of the <a
   *     href="../je/OperationFailureException.html#writeFailures">Write Operation Failures</a>
   *     occurs.
   * @throws EnvironmentFailureException if an unexpected, internal or environment-wide failure
   *     occurs.
   * @throws IllegalArgumentException if the delta is less than or equal to zero, or larger than the
   *     size of the sequence's range.
   */
  public synchronized long get(Transaction txn, int delta) throws DatabaseException {

    /* Check parameters, being careful of overflow. */
    if (delta <= 0) {
      throw new IllegalArgumentException("Sequence delta must be greater than zero");
    }
    if (rangeMin > rangeMax - delta) {
      throw new IllegalArgumentException("Sequence delta is larger than the range");
    }

    /* Status variables for tracing. */
    boolean cached = true;
    boolean wrapped = false;

    /*
     * Determine whether we have exceeded the cache.  The cache size is
     * always <= Integer.MAX_VALUE, so we don't have to worry about
     * overflow here as long as we subtract the two long values first.
     */
    if ((increment && delta > ((cacheLast - cacheValue) + 1))
        || (!increment && delta > ((cacheValue - cacheLast) + 1))) {

      cached = false;

      /*
       * We need to allocate delta or cacheSize values, whichever is
       * larger, by incrementing or decrementing the stored value by
       * adjust.
       */
      int adjust = (delta > cacheSize) ? delta : cacheSize;

      /* Perform an auto-commit transaction to update the sequence. */
      Locker locker = null;
      Cursor cursor = null;
      OperationStatus status = OperationStatus.NOTFOUND;
      try {
        locker =
            LockerFactory.getWritableLocker(
                db.getEnvironment(),
                txn,
                db.isTransactional(),
                false, // retainNonTxnLocks
                db.getDatabaseImpl().isReplicated(),
                // autoTxnIsReplicated
                autoCommitConfig);

        cursor = new Cursor(db, locker, null);

        /* Get the existing record. */
        readDataRequired(cursor, LockMode.RMW);

        /* If we would have wrapped when not allowed, overflow. */
        if (overflow) {
          throw new SequenceOverflowException("Sequence overflow " + storedValue);
        }

        /*
         * Handle wrapping.  The range size can be larger than a long
         * can hold, so to avoid arithmetic overflow we use BigInteger
         * arithmetic.  Since we are going to write, the BigInteger
         * overhead is acceptable.
         */
        BigInteger availBig;
        if (increment) {
          /* Available amount: rangeMax - storedValue */
          availBig = BigInteger.valueOf(rangeMax).subtract(BigInteger.valueOf(storedValue));
        } else {
          /* Available amount: storedValue - rangeMin */
          availBig = BigInteger.valueOf(storedValue).subtract(BigInteger.valueOf(rangeMin));
        }

        if (availBig.compareTo(BigInteger.valueOf(adjust)) < 0) {
          /* If availBig < adjust then availBig fits in an int. */
          int availInt = (int) availBig.longValue();
          if (availInt < delta) {
            if (wrapAllowed) {
              /* Wrap to the opposite range end point. */
              storedValue = increment ? rangeMin : rangeMax;
              wrapped = true;
            } else {
              /* Signal an overflow next time. */
              overflow = true;
              adjust = 0;
            }
          } else {

            /*
             * If the delta fits in the cache available, don't wrap
             * just to allocate the full cacheSize; instead,
             * allocate as much as is available.
             */
            adjust = availInt;
          }
        }

        /* Negate the adjustment for decrementing. */
        if (!increment) {
          adjust = -adjust;
        }

        /* Set the stored value one past the cached amount. */
        storedValue += adjust;

        /* Write the new stored value. */
        cursor.put(key, makeData());
        status = OperationStatus.SUCCESS;
      } finally {
        if (cursor != null) {
          cursor.close();
        }
        if (locker != null) {
          locker.operationEnd(status);
        }
      }

      /* The cache now contains the range: [cacheValue, storedValue) */
      cacheValue = storedValue - adjust;
      cacheLast = storedValue + (increment ? (-1) : 1);
    }

    /* Return the current value and increment/decrement it by delta. */
    long retVal = cacheValue;
    if (increment) {
      cacheValue += delta;
    } else {
      cacheValue -= delta;
    }

    /* Increment stats. */
    nGets += 1;
    if (cached) {
      nCachedGets += 1;
    }

    /* Trace this method at the FINEST level. */
    if (logger.isLoggable(Level.FINEST)) {
      LoggerUtils.finest(
          logger,
          db.getEnvironment().getEnvironmentImpl(),
          "Sequence.get" + " value=" + retVal + " cached=" + cached + " wrapped=" + wrapped);
    }

    return retVal;
  }