예제 #1
0
  public int previousIndex() {

    if (!coll.view.recNumAccess) {
      throw new UnsupportedOperationException("Record number access not supported");
    }

    return hasPrevious() ? (getRecordNumber(nextIndex - 1) - coll.getIndexOffset()) : (-1);
  }
예제 #2
0
  public int nextIndex() {

    if (!coll.view.recNumAccess) {
      throw new UnsupportedOperationException("Record number access not supported");
    }

    return hasNext() ? (getRecordNumber(nextIndex) - coll.getIndexOffset()) : Integer.MAX_VALUE;
  }
예제 #3
0
  /** Sets dataObject to the iterator data for the element at dataIndex. */
  private void makeDataObject() {

    int i = dataIndex;
    DatabaseEntry keyEntry = new DatabaseEntry(keys[i]);
    DatabaseEntry priKeyEntry = (keys != priKeys) ? (new DatabaseEntry(priKeys[i])) : keyEntry;
    DatabaseEntry valuesEntry = new DatabaseEntry(values[i]);

    dataObject = coll.makeIteratorData(this, keyEntry, priKeyEntry, valuesEntry);
  }
예제 #4
0
  public void set(E value) {

    if (dataObject == null) {
      throw new IllegalStateException();
    }
    if (!coll.hasValues()) {
      throw new UnsupportedOperationException();
    }
    DataCursor cursor = null;
    boolean doAutoCommit = coll.beginAutoCommit();
    try {
      cursor = new DataCursor(coll.view, writeAllowed);
      if (moveCursor(dataIndex, cursor)) {
        cursor.putCurrent(value);
        setSlot(dataIndex, cursor);
        coll.closeCursor(cursor);
        coll.commitAutoCommit(doAutoCommit);
      } else {
        throw new IllegalStateException();
      }
    } catch (Exception e) {
      coll.closeCursor(cursor);
      throw coll.handleException(e, doAutoCommit);
    }
  }
예제 #5
0
  /** Copy constructor. */
  private BlockIterator(BlockIterator<E> o) {

    coll = o.coll;
    writeAllowed = o.writeAllowed;

    keys = copyArray(o.keys);
    priKeys = coll.isSecondary() ? copyArray(o.priKeys) : keys;
    values = copyArray(o.values);

    nextIndex = o.nextIndex;
    dataIndex = o.dataIndex;
    dataObject = o.dataObject;
  }
예제 #6
0
  /** Creates an iterator. */
  BlockIterator(StoredCollection<E> coll, boolean writeAllowed, int blockSize) {

    this.coll = coll;
    this.writeAllowed = writeAllowed;

    keys = new byte[blockSize][];
    priKeys = coll.isSecondary() ? (new byte[blockSize][]) : keys;
    values = new byte[blockSize][];

    nextIndex = blockSize;
    dataIndex = -1;
    dataObject = null;
  }
예제 #7
0
  public Object setValue(Object newValue) {

    Object oldValue;
    if (iter != null && iter.isCurrentData(this)) {
      oldValue = getValue();
      iter.set(newValue);
    } else {
      if (coll.view.dupsAllowed) {
        throw new IllegalStateException("May not insert duplicates");
      }
      oldValue = coll.put(getKey(), newValue);
    }
    setValueInternal(newValue);
    return oldValue;
  }
예제 #8
0
  public void add(E value) {

    /*
     * The checkIterAddAllowed method ensures that one of the following two
     * conditions holds and throws UnsupportedOperationException otherwise:
     * 1- This is a list iterator for a recno-renumber database.
     * 2- This is a collection iterator for a duplicates database.
     */
    coll.checkIterAddAllowed();
    OperationStatus status = OperationStatus.SUCCESS;
    DataCursor cursor = null;
    boolean doAutoCommit = coll.beginAutoCommit();
    try {
      if (coll.view.keysRenumbered || !coll.areDuplicatesOrdered()) {

        /*
         * This is a recno-renumber database or a btree/hash database
         * with unordered duplicates.
         */
        boolean hasPrev = hasPrevious();
        if (!hasPrev && !hasNext()) {

          /* The collection is empty. */
          if (coll.view.keysRenumbered) {

            /* Append to an empty recno-renumber database. */
            status = coll.view.append(value, null, null);

          } else if (coll.view.dupsAllowed && coll.view.range.isSingleKey()) {

            /*
             * When inserting a duplicate into a single-key range,
             * the main key is fixed, so we can always insert into
             * an empty collection.
             */
            cursor = new DataCursor(coll.view, writeAllowed);
            cursor.useRangeKey();
            status = cursor.putNoDupData(null, value, null, true);
            coll.closeCursor(cursor);
            cursor = null;
          } else {
            throw new IllegalStateException("Collection is empty, cannot add() duplicate");
          }

          /*
           * Move past the record just inserted (the cursor should be
           * closed above to prevent multiple open cursors in certain
           * DB core modes).
           */
          if (status == OperationStatus.SUCCESS) {
            next();
            dataIndex = nextIndex - 1;
          }
        } else {

          /*
           * The collection is non-empty.  If hasPrev is true then
           * the element at (nextIndex - 1) is available; otherwise
           * the element at nextIndex is available.
           */
          cursor = new DataCursor(coll.view, writeAllowed);
          int insertIndex = hasPrev ? (nextIndex - 1) : nextIndex;

          if (!moveCursor(insertIndex, cursor)) {
            throw new IllegalStateException();
          }

          /*
           * For a recno-renumber database or a database with
           * unsorted duplicates, insert before the iterator 'next'
           * position, or after the 'prev' position.  Then adjust
           * the slots to account for the inserted record.
           */
          status = hasPrev ? cursor.putAfter(value) : cursor.putBefore(value);
          if (status == OperationStatus.SUCCESS) {
            insertSlot(nextIndex, cursor);
          }
        }
      } else {
        /* This is a btree/hash database with ordered duplicates. */
        cursor = new DataCursor(coll.view, writeAllowed);

        if (coll.view.range.isSingleKey()) {

          /*
           * When inserting a duplicate into a single-key range,
           * the main key is fixed.
           */
          cursor.useRangeKey();
        } else {

          /*
           * When inserting into a multi-key range, the main key
           * is the last dataIndex accessed by next(), previous()
           * or add().
           */
          if (dataIndex < 0 || !moveCursor(dataIndex, cursor)) {
            throw new IllegalStateException();
          }
        }

        /*
         * For a hash/btree with duplicates, insert the duplicate,
         * put the new record in slot zero, and set the next index
         * to slot one (past the new record).
         */
        status = cursor.putNoDupData(null, value, null, true);
        if (status == OperationStatus.SUCCESS) {
          clearSlots();
          setSlot(0, cursor);
          dataIndex = 0;
          nextIndex = 1;
        }
      }

      if (status == OperationStatus.KEYEXIST) {
        throw new IllegalArgumentException("Duplicate value");
      } else if (status != OperationStatus.SUCCESS) {
        throw new IllegalArgumentException("Could not insert: " + status);
      }

      /* Prevent subsequent set() or remove() call. */
      dataObject = null;

      coll.closeCursor(cursor);
      coll.commitAutoCommit(doAutoCommit);
    } catch (Exception e) {
      /* Catch RuntimeExceptions too. */
      coll.closeCursor(cursor);
      throw coll.handleException(e, doAutoCommit);
    }
  }
예제 #9
0
  public void remove() {

    if (dataObject == null) {
      throw new IllegalStateException();
    }
    DataCursor cursor = null;
    boolean doAutoCommit = coll.beginAutoCommit();
    try {
      cursor = new DataCursor(coll.view, writeAllowed);
      if (moveCursor(dataIndex, cursor)) {
        cursor.delete();
        deleteSlot(dataIndex);
        dataObject = null;

        /*
         * Repopulate the block after removing all records, using the
         * cursor position of the deleted record as a starting point.
         * First try moving forward, since the user was moving forward.
         * (It is possible to delete all records in the block only by
         * moving forward, i.e, when nextIndex is greater than
         * dataIndex.)
         */
        if (nextIndex == 0 && keys[0] == null) {
          OperationStatus status;
          for (int i = 0; i < keys.length; i += 1) {
            status = coll.iterateDuplicates() ? cursor.getNext(false) : cursor.getNextNoDup(false);
            if (status == OperationStatus.SUCCESS) {
              setSlot(i, cursor);
            } else {
              break;
            }
          }

          /*
           * If no records are found past the cursor position, try
           * moving backward.  If no records are found before the
           * cursor position, leave nextIndex set to keys.length,
           * which is the same as the initial iterator state and is
           * appropriate for an empty key range.
           */
          if (keys[0] == null) {
            nextIndex = keys.length;
            for (int i = nextIndex - 1; i >= 0; i -= 1) {
              status =
                  coll.iterateDuplicates() ? cursor.getPrev(false) : cursor.getPrevNoDup(false);
              if (status == OperationStatus.SUCCESS) {
                setSlot(i, cursor);
              } else {
                break;
              }
            }
          }
        }
        coll.closeCursor(cursor);
        coll.commitAutoCommit(doAutoCommit);
      } else {
        throw new IllegalStateException();
      }
    } catch (Exception e) {
      coll.closeCursor(cursor);
      throw coll.handleException(e, doAutoCommit);
    }
  }
예제 #10
0
  public boolean hasPrevious() {

    if (isPrevAvailable()) {
      return true;
    }
    if (!isNextAvailable()) {
      return false;
    }
    DataCursor cursor = null;
    try {
      cursor = new DataCursor(coll.view, writeAllowed);
      int last = keys.length - 1;
      int next = nextIndex;
      boolean found = false;

      /* Reposition to the last known key/data pair. */
      int repos = cursor.repositionRange(keys[next], priKeys[next], values[next], false);

      if (repos == DataCursor.REPOS_EXACT || repos == DataCursor.REPOS_NEXT) {

        /*
         * The last known key/data pair, or the record following it,
         * was found and will now be in the last slot.
         */
        found = true;
        nextIndex = last;

        /* The data object is now in the last slot or not available. */
        if (dataIndex == next && repos == DataCursor.REPOS_EXACT) {
          dataIndex = last;
        } else {
          dataIndex = -1;
          dataObject = null;
        }
      } else {
        if (repos != DataCursor.REPOS_EOF) {
          throw new IllegalStateException();
        }
      }

      if (found) {
        /* Clear all slots first in case an exception occurs below. */
        clearSlots();

        /* Attempt to fill all slots with records. */
        int i = last;
        boolean done = false;
        while (!done) {
          setSlot(i, cursor);
          i -= 1;
          if (i >= 0) {
            OperationStatus status =
                coll.iterateDuplicates() ? cursor.getPrev(false) : cursor.getPrevNoDup(false);
            if (status != OperationStatus.SUCCESS) {
              done = true;
            }
          } else {
            done = true;
          }
        }
      }

      /*
       * Make sure we retrieved the preceding record after the reposition
       * above.
       */
      return isPrevAvailable();
    } catch (DatabaseException e) {
      throw StoredContainer.convertException(e);
    } finally {
      closeCursor(cursor);
    }
  }
예제 #11
0
  public boolean hasNext() {

    if (isNextAvailable()) {
      return true;
    }
    DataCursor cursor = null;
    try {
      cursor = new DataCursor(coll.view, writeAllowed);
      int prev = nextIndex - 1;
      boolean found = false;

      if (keys[prev] == null) {
        /* Get the first record for an uninitialized iterator. */
        OperationStatus status = cursor.getFirst(false);
        if (status == OperationStatus.SUCCESS) {
          found = true;
          nextIndex = 0;
        }
      } else {
        /* Reposition to the last known key/data pair. */
        int repos = cursor.repositionRange(keys[prev], priKeys[prev], values[prev], false);

        if (repos == DataCursor.REPOS_EXACT) {

          /*
           * The last known key/data pair was found and will now be
           * in slot zero.
           */
          found = true;
          nextIndex = 1;

          /* The data object is now in slot zero or not available. */
          if (dataIndex == prev) {
            dataIndex = 0;
          } else {
            dataIndex = -1;
            dataObject = null;
          }
        } else if (repos == DataCursor.REPOS_NEXT) {

          /*
           * The last known key/data pair was not found, but the
           * following record was found and it will be in slot zero.
           */
          found = true;
          nextIndex = 0;

          /* The data object is no longer available. */
          dataIndex = -1;
          dataObject = null;
        } else {
          if (repos != DataCursor.REPOS_EOF) {
            throw new IllegalStateException();
          }
        }
      }

      if (found) {
        /* Clear all slots first in case an exception occurs below. */
        clearSlots();

        /* Attempt to fill all slots with records. */
        int i = 0;
        boolean done = false;
        while (!done) {
          setSlot(i, cursor);
          i += 1;
          if (i < keys.length) {
            OperationStatus status =
                coll.iterateDuplicates() ? cursor.getNext(false) : cursor.getNextNoDup(false);
            if (status != OperationStatus.SUCCESS) {
              done = true;
            }
          } else {
            done = true;
          }
        }
      }

      /*
       * If REPOS_EXACT was returned above, make sure we retrieved
       * the following record.
       */
      return isNextAvailable();
    } catch (DatabaseException e) {
      throw StoredContainer.convertException(e);
    } finally {
      closeCursor(cursor);
    }
  }