Package com.sleepycat.je.txn

Examples of com.sleepycat.je.txn.BasicLocker


        boolean ret = false;
        boolean setNewIdKey = false;
        boolean anyLocksDenied = false;
  DatabaseImpl db = getDatabase();
        BasicLocker lockingTxn = new BasicLocker(db.getDbEnvironment());

        try {
            for (int i = 0; i < getNEntries(); i++) {

    /*
     * We have to be able to lock the LN before we can compress the
     * entry.  If we can't, then, skip over it.
     *
     * We must lock the LN even if isKnownDeleted is true, because
     * locks protect the aborts. (Aborts may execute multiple
     * operations, where each operation latches and unlatches. It's
     * the LN lock that protects the integrity of the whole
     * multi-step process.)
                 *
                 * For example, during abort, there may be cases where we have
     * deleted and then added an LN during the same txn.  This
     * means that to undo/abort it, we first delete the LN (leaving
     * knownDeleted set), and then add it back into the tree.  We
     * want to make sure the entry is in the BIN when we do the
     * insert back in.
     */
                boolean deleteEntry = false;

                if (binRef == null ||
        isEntryPendingDeleted(i) ||
                    isEntryKnownDeleted(i) ||
                    binRef.hasDeletedKey(new Key(getKey(i)))) {

                    Node n = null;
                    if (canFetch) {
                        n = fetchTarget(i);
                    } else {
                        n = getTarget(i);
                        if (n == null) {
                            /* Punt, we don't know the state of this child. */
                            continue;
                        }
                    }

                    if (n == null) {
                        /* Cleaner deleted the log file.  Compress this LN. */
                        deleteEntry = true;
                    } else if (isEntryKnownDeleted(i)) {
                        LockResult lockRet = lockingTxn.nonBlockingLock
                            (n.getNodeId(), LockType.READ, db);
                        if (lockRet.getLockGrant() == LockGrantType.DENIED) {
                            anyLocksDenied = true;
                            continue;
                        }

                        deleteEntry = true;
                    } else {
                        if (!n.containsDuplicates()) {
                            LN ln = (LN) n;
                            LockResult lockRet = lockingTxn.nonBlockingLock
                                (ln.getNodeId(), LockType.READ, db);
                            if (lockRet.getLockGrant() ==
                                LockGrantType.DENIED) {
                                anyLocksDenied = true;
                                continue;
                            }

                            if (ln.isDeleted()) {
                                deleteEntry = true;
                            }
                        }
                    }

                    /* Remove key from BINReference in case we requeue it. */
                    if (binRef != null) {
                        binRef.removeDeletedKey(new Key(getKey(i)));
                    }
                }

                /* At this point, we know we can delete. */
                if (deleteEntry) {
                    boolean entryIsIdentifierKey = Key.compareKeys
                        (getKey(i), getIdentifierKey(),
                         getKeyComparator()) == 0;
                    if (entryIsIdentifierKey) {

                        /*
                         * We're about to remove the entry with the idKey so
                         * the node will need a new idkey.
                         */
                        setNewIdKey = true;
                    }

                    boolean deleteSuccess = deleteEntry(i, true);
                    assert deleteSuccess;

                    /*
                     * Since we're deleting the current entry, bump the current
                     * index back down one.
                     */
                    i--;
                }
            }
        } finally {
            if (lockingTxn != null) {
                lockingTxn.operationEnd();
            }
        }

        if (anyLocksDenied && binRef != null) {
            db.getDbEnvironment().addToCompressorQueue(binRef, false);
View Full Code Here


     */
    private void removeTempDbs()
        throws DatabaseException {

        DbTree dbMapTree = envImpl.getDbTree();
        BasicLocker locker =
            BasicLocker.createBasicLocker(envImpl, false /*noWait*/);
        boolean operationOk = false;
        try {
            Iterator<DatabaseId> removeDbs = tempDbIds.iterator();
            while (removeDbs.hasNext()) {
                DatabaseId dbId = removeDbs.next();
                DatabaseImpl db = dbMapTree.getDb(dbId);
                dbMapTree.releaseDb(db); // Decrement use count.
                if (db != null) {
                    assert db.isTemporary();
                    if (!db.isDeleted()) {
                        try {
                            envImpl.getDbTree().dbRemove(locker,
                                                         db.getName(),
                                                         db.getId());
                        } catch (DatabaseNotFoundException e) {
                            throw EnvironmentFailureException.
                                unexpectedException(e);
                        }
                    }
                }
            }
            operationOk = true;
        } catch (Error E) {
            envImpl.invalidate(E);
            throw E;
        } finally {
            locker.operationEnd(operationOk);
        }
    }
View Full Code Here

        boolean migrated = false// The LN was in use and is migrated.
        boolean lockDenied = false;// The LN lock was denied.
        boolean completed = false; // This method completed.

        long nodeId = lnFromLog.getNodeId();
        BasicLocker locker = null;
        try {
            Tree tree = db.getTree();
            assert tree != null;

            /*
             * If the tree and log LSNs are equal, then we can be fairly
             * certain that the log entry is current; in that case, it is
             * wasteful to lock the LN here if we will perform lazy migration
             * -- it is better to lock only once during lazy migration.  But if
             * the tree and log LSNs differ, it is likely that another thread
             * has updated or deleted the LN and the log LSN is now obsolete;
             * in this case we can avoid dirtying the BIN by checking for
             * obsoleteness here, which requires locking.  The latter case can
             * occur frequently if trackDetail is false.
             *
             * 1. If the LSN in the tree and in the log are the same, we will
             * attempt to migrate it.
             *
             * 2. If the LSN in the tree is < the LSN in the log, the log entry
             * is obsolete, because this LN has been rolled back to a previous
             * version by a txn that aborted.
             *
             * 3. If the LSN in the tree is > the LSN in the log, the log entry
             * is obsolete, because the LN was advanced forward by some
             * now-committed txn.
             *
             * 4. If the LSN in the tree is a null LSN, the log entry is
             * obsolete. A slot can only have a null LSN if the record has
             * never been written to disk in a deferred write database, and
             * in that case the log entry must be for a past, deleted version
             * of that record.
             */
            if (lnFromLog.isDeleted() &&
                (treeLsn == logLsn) &&
                fileLogVersion <= 2) {

                /*
                 * SR 14583: After JE 2.0, deleted LNs are never found in the
                 * tree, since we can assume they're obsolete and correctly
                 * marked as such in the obsolete offset tracking. JE 1.7.1 and
                 * earlier did not use the pending deleted bit, so deleted LNs
                 * may still be reachable through their BIN parents.
                 */
                obsolete = true;
                nLNsDeadThisRun++;
                bin.setPendingDeleted(index);
            } else if (treeLsn == DbLsn.NULL_LSN) {

                /*
                 * Case 4: The LN in the tree is a never-written LN for a
                 * deferred-write db, so the LN in the file is obsolete.
                 */
                obsolete = true;
            } else if (treeLsn != logLsn && isTemporary) {

                /*
                 * Temporary databases are always non-transactional.  If the
                 * tree and log LSNs are different then we know that the logLsn
                 * is obsolete.  Even if the LN is locked, the tree cannot be
                 * restored to the logLsn because no abort is possible without
                 * a transaction.  We should consider a similar optimization in
                 * the future for non-transactional durable databases.
                 */
                nLNsDeadThisRun++;
                obsolete = true;
            } else if (treeLsn != logLsn || !cleaner.lazyMigration) {

                /*
                 * Get a lock on the LN if the treeLsn and logLsn are different
                 * to determine definitively whether the logLsn is obsolete.
                 * We must also get a lock if we will migrate the LN now
                 * (lazyMigration is false).
                 *
                 * We can hold the latch on the BIN (and DIN) since we always
                 * attempt to acquire a non-blocking read lock.
                 */
                locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
                /* Don't allow this short-lived lock to be preempted/stolen. */
                locker.setPreemptable(false);
                LockResult lockRet = locker.nonBlockingLock
                    (nodeId, LockType.READ, db);
                if (lockRet.getLockGrant() == LockGrantType.DENIED) {

                    /*
                     * LN is currently locked by another Locker, so we can't
                     * assume anything about the value of the LSN in the bin.
                     */
                    nLNsLockedThisRun++;
                    lockDenied = true;
                } else if (treeLsn != logLsn) {
                    /* The LN is obsolete and can be purged. */
                    nLNsDeadThisRun++;
                    obsolete = true;
                }
            }

            /*
             * At this point either obsolete==true, lockDenied==true, or
             * treeLsn==logLsn.
             */
            if (!obsolete && !lockDenied) {
                assert treeLsn == logLsn;

                /*
                 * If lazyMigration is true, set the migrate flag and dirty
                 * the parent IN.  The evictor or checkpointer will migrate the
                 * LN later.  If lazyMigration is false, migrate the LN now.
                 *
                 * We have a lock on the LN if we are going to migrate it now,
                 * but not if we will set the migrate flag.
                 *
                 * When setting the migrate flag, also populate the target node
                 * so it does not have to be fetched when it is migrated, if
                 * the tree and log LSNs are equal and the target is not
                 * resident.  We must call postFetchInit to initialize MapLNs
                 * that have not been fully initialized yet [#13191].
                 *
                 * For temporary databases, do not rely on the LN migration
                 * mechanism because temporary databases are not checkpointed
                 * or recovered.  Instead, dirty the LN to ensure it is
                 * flushed before its parent is written, and set the LSN to
                 * NULL_LSN to ensure that it is not tracked or otherwise
                 * referenced.  Because we do not attempt to lock temporary
                 * database LNs (see above) we know that if it is non-obsolete,
                 * the tree and log LSNs are equal.  We will always restore the
                 * LN to the BIN slot here, and always log the dirty LN when
                 * logging the BIN.
                 *
                 * Also for temporary databases, make both the target LN and
                 * the BIN or IN parent dirty. Otherwise, when the BIN or IN is
                 * evicted in the future, it will be written to disk without
                 * flushing its dirty, migrated LNs.  [#18227]
                 */
                if (isDupCountLN) {
                    ChildReference dclRef = parentDIN.getDupCountLNRef();
                    if (dclRef.getTarget() == null) {
                        lnFromLog.postFetchInit(db, logLsn);
                        parentDIN.updateDupCountLN(lnFromLog);
                    }

                    if (isTemporary) {
                        ((LN) dclRef.getTarget()).setDirty();
                        dclRef.setLsn(DbLsn.NULL_LSN);
                        parentDIN.setDirty(true);
                    } else if (cleaner.lazyMigration) {
                        dclRef.setMigrate(true);
                        parentDIN.setDirty(true);
                    } else {
                        LN targetLn = (LN) dclRef.getTarget();
                        assert targetLn != null;
                        byte[] targetKey = parentDIN.getDupKey();
                        long newLNLsn = targetLn.log
                            (env, db, targetKey, logLsn, locker,
                             true /*backgroundIO*/,
                             ReplicationContext.NO_REPLICATE);
                        parentDIN.updateDupCountLNRef(newLNLsn);
                        /* Evict LN if we populated it with the log LN. */
                        if (lnFromLog == targetLn) {
                            parentDIN.updateDupCountLN(null);
                        }
                    }
                } else {
                    if (bin.getTarget(index) == null) {
                        lnFromLog.postFetchInit(db, logLsn);
                        /* Ensure keys are transactionally correct. [#15704] */
                        byte[] lnSlotKey = bin.containsDuplicates() ?
                            dupKey : key;
                        bin.updateNode(index, lnFromLog, lnSlotKey);
                    }

                    if (isTemporary) {
                        ((LN) bin.getTarget(index)).setDirty();
                        bin.clearLsn(index);
                        bin.setDirty(true);
                    } else if (cleaner.lazyMigration) {
                        bin.setMigrate(index, true);
                        bin.setDirty(true);
                    } else {
                        LN targetLn = (LN) bin.getTarget(index);
                        assert targetLn != null;
                        byte[] targetKey = cleaner.getLNMainKey(bin, index);
                        long newLNLsn = targetLn.log
                            (env, db, targetKey, logLsn, locker,
                             true /*backgroundIO*/,
                             ReplicationContext.NO_REPLICATE);
                        bin.updateEntry(index, newLNLsn);
                        /* Evict LN if we populated it with the log LN. */
                        if (lnFromLog == targetLn) {
                            bin.updateNode(index, null, null);
                        }
                    }

                    /*
                     * If the generation is zero, we fetched this BIN just for
                     * cleaning.
                     */
                    if (PROHIBIT_DELTAS_WHEN_FETCHING &&
                        bin.getGeneration() == 0) {
                        bin.setProhibitNextDelta();
                    }

                    /*
                     * Update the generation so that the BIN is not evicted
                     * immediately.  This allows the cleaner to fill in as many
                     * entries as possible before eviction, as to-be-cleaned
                     * files are processed.
                     */
                    bin.setGeneration(CacheMode.DEFAULT);
                }

                nLNsMarkedThisRun++;
                migrated = true;
            }
            completed = true;
        } finally {
            if (locker != null) {
                locker.operationEnd();
            }

            /*
             * If a write lock is held, it is likely that the log LSN will
             * become obsolete.  It is more efficient to process this via the
View Full Code Here

        boolean processedHere = true; // The LN was cleaned here.
        boolean lockDenied = false;   // The LN lock was denied.
        boolean obsolete = false;     // The LN is no longer in use.
        boolean completed = false;    // This method completed.

        BasicLocker locker = null;
        BIN bin = null;
        DIN parentDIN = null;
        try {
            nPendingLNsProcessed.increment();

            /*
             * If the DB is gone, this LN is obsolete.  If delete cleanup is in
             * progress, put the DB into the DB pending set; this LN will be
             * declared deleted after the delete cleanup is finished.
             */
            if (db == null || db.isDeleted()) {
                addPendingDB(db);
                nLNsDead.increment();
                obsolete = true;
                completed = true;
                return;
            }

            Tree tree = db.getTree();
            assert tree != null;

            /* Get a non-blocking lock on the original node ID. */

            locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
            /* Don't allow this short-lived lock to be preempted/stolen. */
            locker.setPreemptable(false);
            LockResult lockRet = locker.nonBlockingLock
                (ln.getNodeId(), LockType.READ, db);
            if (lockRet.getLockGrant() == LockGrantType.DENIED) {
                /* Try again later. */
                nPendingLNsLocked.increment();
                lockDenied = true;
                completed = true;
                return;
            }

            /*
             * Search down to the bottom most level for the parent of this LN.
             *
             * We pass searchDupTree=true to search the dup tree by nodeID if
             * necessary.  This handles the case where dupKey is null because
             * the pending entry was a deleted single-duplicate in a BIN.
             */
            parentFound = tree.getParentBINForChildLN
                (location, key, dupKey, ln,
                 false,  // splitsAllowed
                 true,   // findDeletedEntries
                 true,   // searchDupTree
                 UPDATE_GENERATION);
            bin = location.bin;
            int index = location.index;

            if (!parentFound) {
                nLNsDead.increment();
                obsolete = true;
                completed = true;
                return;
            }

            if (ln.containsDuplicates()) {
                /* Migrate a DupCountLN. */
                parentDIN = (DIN) bin.fetchTarget(index);
                parentDIN.latch(UPDATE_GENERATION);
                ChildReference dclRef = parentDIN.getDupCountLNRef();
                processedHere = false;
                migrateDupCountLN
                    (db, dclRef.getLsn(), parentDIN, dclRef,
                     true,           // wasCleaned
                     true,           // isPending
                     ln.getNodeId(), // lockedPendingNodeId
                     CLEAN_PENDING_LN);
            } else {
                /* Migrate a plain LN. */
                processedHere = false;
                migrateLN
                    (db, bin.getLsn(index), bin, index,
                     true,           // wasCleaned
                     true,           // isPending
                     ln.getNodeId(), // lockedPendingNodeId
                     true,           // backgroundIO
                     CLEAN_PENDING_LN);
            }
            completed = true;
        } catch (DatabaseException DBE) {
            DBE.printStackTrace();
            LoggerUtils.traceAndLogException
                (env, "com.sleepycat.je.cleaner.Cleaner",
                 "processLN", "Exception thrown: ", DBE);
            throw DBE;
        } finally {
            if (parentDIN != null) {
                parentDIN.releaseLatch();
            }

            if (bin != null) {
                bin.releaseLatch();
            }

            if (locker != null) {
                locker.operationEnd();
            }

            /*
             * If migrateLN was not called above, remove the pending LN and
             * perform tracing in this method.
View Full Code Here

        /*
         * If wasCleaned is false we don't count statistics unless we migrate
         * the LN.  This avoids double counting.
         */
        BasicLocker locker = null;
        LN ln = null;

        try {
            if (lsn == DbLsn.NULL_LSN) {
                /* This node was never written, no need to migrate. */
                completed = true;
                return;
            }

            /*
             * Fetch the node, if necessary.  If it was not resident and it is
             * an evictable LN, we will clear it after we migrate it.
             */
            if (!bin.isEntryKnownDeleted(index)) {
                ln = (LN) bin.getTarget(index);
                if (ln == null) {
                    /* If fetchTarget returns null, a deleted LN was cleaned.*/
                    ln = (LN) bin.fetchTarget(index);
                    clearTarget = !db.getId().equals(DbTree.ID_DB_ID);
                }
            }

            /* Don't migrate knownDeleted or deleted cleaned LNs.  */
            if (ln == null) {
                if (wasCleaned) {
                    nLNsDead.increment();
                }
                obsolete = true;
                completed = true;
                return;
            }

            /*
             * Get a non-blocking read lock on the LN.  A pending node is
             * already locked, but that node ID may be different than the
             * current LN's node if a slot is reused.  We must lock the current
             * node to guard against aborts.
             */
            if (lockedPendingNodeId != ln.getNodeId()) {
                locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
                /* Don't allow this short-lived lock to be preempted/stolen. */
                locker.setPreemptable(false);
                LockResult lockRet = locker.nonBlockingLock
                    (ln.getNodeId(), LockType.READ, db);
                if (lockRet.getLockGrant() == LockGrantType.DENIED) {

                    /*
                     * LN is currently locked by another Locker, so we can't
                     * assume anything about the value of the LSN in the bin.
                     */
                    if (wasCleaned) {
                        nLNsLocked.increment();
                    }
                    lockDenied = true;
                    completed = true;
                    return;
                }
            }

            /* Don't migrate deleted LNs.  */
            if (ln.isDeleted()) {
                bin.setKnownDeletedLeaveTarget(index);
                if (wasCleaned) {
                    nLNsDead.increment();
                }
                obsolete = true;
                completed = true;
                return;
            }

            /*
             * Once we have a lock, check whether the current LSN needs to be
             * migrated.  There is no need to migrate it if the LSN no longer
             * qualifies for cleaning.  The LSN could have been changed by an
             * update or delete after we set the MIGRATE flag.
             *
             * Note that we do not perform this optimization if the MIGRATE
             * flag is not set, i.e, for clustering and proactive migration of
             * resident LNs.  For these cases, we checked the conditions for
             * migration immediately before calling this method.  Although the
             * condition could change after locking, the window is small and
             * a second check is not worthwhile.
             */
            if (bin.getMigrate(index)) {
                Long fileNum = Long.valueOf(DbLsn.getFileNumber(lsn));
                if (!fileSelector.isFileCleaningInProgress(fileNum)) {
                    obsolete = true;
                    completed = true;
                    if (wasCleaned) {
                        nLNsDead.increment();
                    }
                    return;
                }
            }

            /* Migrate the LN. */
            byte[] key = getLNMainKey(bin, index);
            long newLNLsn = ln.log(env, db, key, lsn, locker, backgroundIO,
                                   ReplicationContext.NO_REPLICATE);
            bin.updateEntry(index, newLNLsn);
            nLNsMigrated.increment();
            migrated = true;
            completed = true;
            return;
        } finally {
            if (isPending) {
                if (completed && !lockDenied) {
                    fileSelector.removePendingLN(lockedPendingNodeId);
                }
            } else {

                /*
                 * If a to-be-migrated LN was not processed successfully, we
                 * must guarantee that the file will not be deleted and that we
                 * will retry the LN later.  The retry information must be
                 * complete or we may delete a file later without processing
                 * all of its LNs.
                 *
                 * Note that the LN may be null if fetchTarget threw an
                 * exception above. [#16039]
                 */
                if (bin.getMigrate(index) &&
                    (!completed || lockDenied) &&
                    (ln != null)) {

                    byte[] key = getLNMainKey(bin, index);
                    byte[] dupKey = getLNDupKey(bin, index, ln);
                    fileSelector.addPendingLN(ln, db.getId(), key, dupKey);

                    /* Wake up the cleaner thread to process pending LNs. */
                    if (!areThreadsRunning()) {
                        env.getUtilizationTracker().activateCleaner();
                    }

                    /*
                     * If we need to retry, don't clear the target since we
                     * would only have to fetch it again soon.
                     */
                    clearTarget = false;
                }
            }

            /*
             * Always clear the migrate flag.  If the LN could not be locked
             * and the migrate flag was set, the LN will have been added to the
             * pending LN set above.
             */
            bin.setMigrate(index, false);

            /*
             * If the node was originally non-resident, clear it now so that we
             * don't create more work for the evictor and reduce the cache
             * memory available to the application.
             */
            if (clearTarget) {
                bin.updateNode(index, null /*node*/, null /*lnSlotKey*/);
            }

            if (locker != null) {
                locker.operationEnd();
            }

            logFine(cleanAction, ln, lsn, completed, obsolete, migrated);
        }
    }
View Full Code Here

        /*
         * If wasCleaned is false we don't count statistics unless we migrate
         * the LN.  This avoids double counting.
         */
        BasicLocker locker = null;
        LN ln = null;

        try {
            if (lsn == DbLsn.NULL_LSN) {
                /* This node was never written, no need to migrate. */
                completed = true;
                return;
            }

            /*
             * Fetch the node, if necessary.  If it was not resident and it is
             * an evictable LN, we will clear it after we migrate it.
             */
            ln = (LN) dclRef.getTarget();
            if (ln == null) {
                ln = (LN) dclRef.fetchTarget(db, parentDIN);
                assert ln != null;
                clearTarget = !db.getId().equals(DbTree.ID_DB_ID);
            }

            /*
             * Get a non-blocking read lock on the LN, if this is not an
             * already locked pending node.
             */
            if (lockedPendingNodeId != ln.getNodeId()) {
                locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
                /* Don't allow this short-lived lock to be preempted/stolen. */
                locker.setPreemptable(false);
                LockResult lockRet = locker.nonBlockingLock
                    (ln.getNodeId(), LockType.READ, db);
                if (lockRet.getLockGrant() == LockGrantType.DENIED) {

                    /*
                     * LN is currently locked by another Locker, so we can't
                     * assume anything about the value of the LSN in the bin.
                     */
                    if (wasCleaned) {
                        nLNsLocked.increment();
                    }
                    lockDenied = true;
                    completed = true;
                    return;
                }
            }

            /*
             * Once we have a lock, check whether the current LSN needs to be
             * migrated.  There is no need to migrate it if the LSN no longer
             * qualifies for cleaning.
             */
            Long fileNum = Long.valueOf(DbLsn.getFileNumber(lsn));
            if (!fileSelector.isFileCleaningInProgress(fileNum)) {
                obsolete = true;
                completed = true;
                if (wasCleaned) {
                    nLNsDead.increment();
                }
                return;
            }

            /* Migrate the LN. */
            byte[] key = parentDIN.getDupKey();
            long newLNLsn = ln.log(env, db, key, lsn, locker,
                                   false, /* backgroundIO */
                                   ReplicationContext.NO_REPLICATE);
            parentDIN.updateDupCountLNRef(newLNLsn);
            nLNsMigrated.increment();
            migrated = true;
            completed = true;
            return;
        } finally {
            if (isPending) {
                if (completed && !lockDenied) {
                    fileSelector.removePendingLN(lockedPendingNodeId);
                }
            } else {

                /*
                 * If a to-be-migrated LN was not processed successfully, we
                 * must guarantee that the file will not be deleted and that we
                 * will retry the LN later.  The retry information must be
                 * complete or we may delete a file later without processing
                 * all of its LNs.
                 *
                 * Note that the LN may be null if fetchTarget threw an
                 * exception above. [#16039]
                 */
                if (dclRef.getMigrate() &&
                    (!completed || lockDenied) &&
                    (ln != null)) {

                    byte[] key = parentDIN.getDupKey();
                    byte[] dupKey = null;
                    fileSelector.addPendingLN(ln, db.getId(), key, dupKey);

                    /* Wake up the cleaner thread to process pending LNs. */
                    if (!areThreadsRunning()) {
                        env.getUtilizationTracker().activateCleaner();
                    }

                    /*
                     * If we need to retry, don't clear the target since we
                     * would only have to fetch it again soon.
                     */
                    clearTarget = false;
                }
            }

            /*
             * Always clear the migrate flag.  If the LN could not be locked
             * and the migrate flag was set, the LN will have been added to the
             * pending LN set above.
             */
            dclRef.setMigrate(false);

            /*
             * If the node was originally non-resident, clear it now so that we
             * don't create more work for the evictor and reduce the cache
             * memory available to the application.
             */
            if (clearTarget) {
                parentDIN.updateDupCountLN(null);
            }

            if (locker != null) {
                locker.operationEnd();
            }

            logFine(cleanAction, ln, lsn, completed, obsolete, migrated);
        }
    }
View Full Code Here

        boolean ret = false;
        boolean setNewIdKey = false;
        boolean anyLocksDenied = false;
  DatabaseImpl db = getDatabase();
        BasicLocker lockingTxn = new BasicLocker(db.getDbEnvironment());

        try {
            for (int i = 0; i < getNEntries(); i++) {

    /*
     * We have to be able to lock the LN before we can compress the
     * entry.  If we can't, then, skip over it.
     *
     * We must lock the LN even if isKnownDeleted is true, because
     * locks protect the aborts. (Aborts may execute multiple
     * operations, where each operation latches and unlatches. It's
     * the LN lock that protects the integrity of the whole
     * multi-step process.)
                 *
                 * For example, during abort, there may be cases where we have
     * deleted and then added an LN during the same txn.  This
     * means that to undo/abort it, we first delete the LN (leaving
     * knownDeleted set), and then add it back into the tree.  We
     * want to make sure the entry is in the BIN when we do the
     * insert back in.
     */
                boolean deleteEntry = false;
                long obsoleteLsn = DbLsn.NULL_LSN;
                if (binRef == null ||
        isEntryPendingDeleted(i) ||
                    isEntryKnownDeleted(i) ||
                    binRef.hasDeletedKey(new Key(getKey(i)))) {

                    Node n = null;
                    if (canFetch) {
                        n = fetchTarget(i);
                    } else {
                        n = getTarget(i);
                        if (n == null) {
                            /* Punt, we don't know the state of this child. */
                            continue;
                        }
                    }

                    if (n == null) {
                        /* Cleaner deleted the log file.  Compress this LN. */
                        deleteEntry = true;
                    } else if (isEntryKnownDeleted(i)) {
                        LockGrantType lockRet =
                            lockingTxn.nonBlockingReadLock(n.getNodeId(), db);
                        if (lockRet == LockGrantType.DENIED) {
                            anyLocksDenied = true;
                            continue;
                        }

                        deleteEntry = true;
                    } else {
                        if (!n.containsDuplicates()) {
                            LN ln = (LN) n;
                            LockGrantType lockRet =
                                lockingTxn.nonBlockingReadLock(ln.getNodeId(),
                     db);
                            if (lockRet == LockGrantType.DENIED) {
                                anyLocksDenied = true;
                                continue;
                            }

                            if (ln.isDeleted()) {
                                deleteEntry = true;
                            }
                        }
                    }

                    if (deleteEntry && n instanceof LN) {
                        obsoleteLsn = getLsn(i);
                    }

                    /* Remove key from BINReference in case we requeue it. */
                    if (binRef != null) {
                        binRef.removeDeletedKey(new Key(getKey(i)));
                    }
                }

                /* At this point, we know we can delete. */
                if (deleteEntry) {
                    Comparator userComparisonFcn = getKeyComparator();
                    boolean entryIsIdentifierKey =
                        (userComparisonFcn == null ?
                         Key.compareKeys(getKey(i), getIdentifierKey()) :
                         userComparisonFcn.compare
       (getKey(i), getIdentifierKey()))
                        == 0;
                    if (entryIsIdentifierKey) {

                        /*
                         * We're about to remove the entry with the idKey so
                         * the node will need a new idkey.
                         */
                        setNewIdKey = true;
                    }

                    boolean deleteSuccess = deleteEntry(i, true);
                    assert deleteSuccess;

                    /*
                     * Since we're deleting the current entry, bump the current
                     * index back down one.
                     */
                    i--;
                }
            }
        } finally {
            if (lockingTxn != null) {
                lockingTxn.operationEnd();
            }
        }

        if (anyLocksDenied && binRef != null) {
            db.getDbEnvironment().addToCompressorQueue(binRef, false);
View Full Code Here

        assert in.getNEntries() > 0;

  DIN duplicateRoot = null;
  boolean dupCountLNLocked = false;
  DupCountLN dcl = null;
  BasicLocker locker = new BasicLocker(env);
        LogManager logManager =
            database.getDbEnvironment().getLogManager();

  try {
            int index = in.findEntry(dupKey, false, true);
      if (index >= 0) {
    duplicateRoot = (DIN) in.fetchTarget(index);
    duplicateRoot.latch();

    ChildReference dclRef = duplicateRoot.getDupCountLNRef();
    dcl = (DupCountLN)
        dclRef.fetchTarget(database, duplicateRoot);

    /* Read lock the dup count LN. */
    if (locker.nonBlockingReadLock(dcl.getNodeId(), database) ==
                    LockGrantType.DENIED) {
        return false;
    } else {
        dupCountLNLocked = true;
    }

    /*
     * We don't release the latch on 'in' before we search the
     * duplicate tree below because we might be deleting the whole
     * subtree from the IN and we want to keep it latched until we
     * know.
     */
    IN subtreeRoot;
    try {
        subtreeRoot = searchSubTree(duplicateRoot,
            idKey,
            SearchType.DELETE,
            -1,
                                                null,
                                                true /*updateGeneration*/);
    } catch (NodeNotEmptyException NNEE) {

        /*
         * We can't delete the subtree because there are still
         * cursors pointing to the lowest node on it.
         */
        in.releaseLatch();
        throw NNEE;
    }

    if (subtreeRoot == null) {
        /* We're deleting the duplicate root. */
        BIN bin = (BIN) in;
        if (bin.nCursors() == 0) {
      try {

          /*
           * duplicateRoot is not currently latched.  Relatch
           * it and recheck if it still is deletable.
           */
          duplicateRoot.latch();
          if (duplicateRoot.isValidForDelete()) {
        boolean deleteOk =
            bin.deleteEntry(index, true);
        assert deleteOk;

        logManager.log(new INDupDeleteInfo
                 (duplicateRoot.getNodeId(),
            duplicateRoot.getMainTreeKey(),
            duplicateRoot.getDupTreeKey(),
            database.getId()));

                                /*
                                 * Count obsolete nodes after logging the
                                 * delete info.
                                 */
                                accountForSubtreeRemoval
            (inMemoryINs, duplicateRoot, tracker);

        if (bin.getNEntries() == 0) {
            database.getDbEnvironment().
          addToCompressorQueue(bin, null, false);
        }
          }
      } finally {
          duplicateRoot.releaseLatch();
      }
        } else {

      /*
       * Don't delete anything off this IN if there are
       * cursors referring to it.
       */
      ret = false;
        }
        in.releaseLatch();
    } else {
        try {
      /* We're deleting a portion of the duplicate tree. */
      in.releaseLatch();
      int dupIndex =
          subtreeRoot.findEntry(idKey, false, false);
      IN rootIN = (IN) subtreeRoot.fetchTarget(dupIndex);
      boolean deleteOk =
          subtreeRoot.deleteEntry(dupIndex, true);
      assert deleteOk;

      /*
       * Record in the log the nodeid of the highest node in
       * the subtree that we're deleting. We'll use this
       * later to navigate to the right place if we need to
       * replay this delete.
       */
      logManager.log(new INDupDeleteInfo
               (rootIN.getNodeId(),
          rootIN.getMainTreeKey(),
          rootIN.getDupTreeKey(),
          database.getId()));

                        /*
                         * Count obsolete nodes after logging the delete info.
                         */
                        accountForSubtreeRemoval(inMemoryINs, rootIN, tracker);
        } finally {
      subtreeRoot.releaseLatch();
        }
    }
      }
  } finally {

      /*
       * Release this IN, either because it didn't prove to be the target
       * IN, or because we threw out of the attempt to delete the
       * subtree.
       */
            in.releaseLatchIfOwner();
      if (duplicateRoot != null) {
    duplicateRoot.releaseLatchIfOwner();
      }

      if (dupCountLNLocked) {
    locker.releaseLock(dcl.getNodeId());
      }
  }

        return ret;
    }
View Full Code Here

TOP

Related Classes of com.sleepycat.je.txn.BasicLocker

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.