Package com.sleepycat.je.txn

Examples of com.sleepycat.je.txn.BasicLocker


        /*
         * 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 the original pending LSN may have changed.
             * We must lock the current LSN to guard against aborts.
             */
            if (lockedPendingLsn != lsn) {
                locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
                /* Don't allow this short-lived lock to be preempted/stolen. */
                locker.setPreemptable(false);
                LockResult lockRet = locker.nonBlockingLock
                    (lsn, LockType.READ, false /*jumpAheadOfWaiters*/, 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.setKnownDeleted(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.
             *
             * Do not pass a locker, because there is no need to lock the new
             * LSN, as done for user operations.  Another locker cannot attempt
             * to lock the new LSN until we're done, because we release the
             * lock before we release the BIN latch.
             */
            long newLNLsn = ln.log(env, db, bin.getKey(index), lsn,
                                   backgroundIO,
                                   getMigrationRepContext(ln));
            bin.updateEntry(index, newLNLsn);
            nLNsMigrated.increment();
            /* Lock new LSN on behalf of existing lockers. */
            CursorImpl.lockAfterLsnChange
                (db, lsn, newLNLsn, locker /*excludeLocker*/);
            migrated = true;
            completed = true;
            return;
        } finally {
            if (isPending) {
                if (completed && !lockDenied) {
                    fileSelector.removePendingLN(lockedPendingLsn);
                }
            } 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)) {

                    fileSelector.addPendingLN(lsn, ln, db.getId(),
                                              bin.getKey(index));

                    /* 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


        boolean evictable = false;

        /* To prevent DB open, get a write-lock on the MapLN. */
        EnvironmentImpl envImpl = databaseImpl.getDbEnvironment();
        BasicLocker locker = BasicLocker.createBasicLocker(envImpl);
        DatabaseImpl idDatabaseImpl = envImpl.getDbTree().getIdDatabaseImpl();
        try {
            LockResult lockResult = locker.nonBlockingLock
                (lsn, LockType.WRITE, false /*jumpAheadOfWaiters*/,
                 idDatabaseImpl);

            /*
             * The isEvictableInexact result is guaranteed to hold true during
             * LN stripping if it is still true after acquiring the write-lock.
             */
            if (lockResult.getLockGrant() != LockGrantType.DENIED &&
                isEvictableInexact()) {

                /*
                 * While holding both a write-lock on the MapLN, we are
                 * guaranteed that the DB is not currently open.  It cannot be
                 * subsequently opened until the BIN latch is released, since
                 * the BIN latch will block DbTree.getDb (called during DB
                 * open).  We will evict the LN before releasing the BIN latch.
                 * After releasing the BIN latch, if a DB open is waiting on
                 * getDb, then it will proceed, fetch the evicted LN and open
                 * the DB normally.
                 */
                evictable = true;
            }
        } finally {
            /* Release the write-lock.  The BIN latch is still held. */
            locker.operationEnd();
        }

        return evictable;
    }
View Full Code Here

            /* Can discard a NULL_LSN entry without locking. */
            return true;
        }

        /* Lock LSN to guarantee deletedness. */
        final BasicLocker lockingTxn = BasicLocker.createBasicLocker(envImpl);
        /* Don't allow this short-lived lock to be preempted/stolen. */
        lockingTxn.setPreemptable(false);
        try {
            final LockResult lockRet = lockingTxn.nonBlockingLock
                (lsn, LockType.READ, false /*jumpAheadOfWaiters*/,
                 checkBin.getDatabase());
            if (lockRet.getLockGrant() == LockGrantType.DENIED) {
                /* Is locked by a resurrected txn. */
                return false;
            }
            return true;
        } finally {
            lockingTxn.operationEnd();
        }
    }
View Full Code Here

        boolean obsolete = false// The LN is no longer in use.
        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.

        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) &&
                       !isTemporary) {

                /*
                 * 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 and isTemporary is false).
                 *
                 * We can hold the latch on the BIN 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
                    (treeLsn, LockType.READ, false /*jumpAheadOfWaiters*/, 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.  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 (bin.getTarget(index) == null) {
                    lnFromLog.postFetchInit(db, logLsn);
                    /* Ensure keys are transactionally correct. [#15704] */
                    bin.updateNode(index, lnFromLog, key /*lnSlotKey*/);
                }

                if (isTemporary) {
                    ((LN) bin.getTarget(index)).setDirty();
                    bin.setDirty(true);
                } else if (cleaner.lazyMigration) {
                    bin.setMigrate(index, true);
                    bin.setDirty(true);
                } else {
                    LN targetLn = (LN) bin.getTarget(index);
                    assert targetLn != null;
                    long newLNLsn = targetLn.log
                        (env, db, bin.getKey(index), logLsn,
                         true /*backgroundIO*/,
                         Cleaner.getMigrationRepContext(targetLn));
                    bin.updateEntry(index, newLNLsn);
                    /* Evict LN if we populated it with the log LN. */
                    if (lnFromLog == targetLn) {
                        bin.updateNode(index, null, null);
                    }
                    /* Lock new LSN on behalf of existing lockers. */
                    CursorImpl.lockAfterLsnChange
                        (db, logLsn, newLNLsn, locker /*excludeLocker*/);
                }

                /*
                 * 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

             * 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.
             */
            final BasicLocker lockingTxn =
                BasicLocker.createBasicLocker(envImpl);
            /* Don't allow this short-lived lock to be preempted/stolen. */
            lockingTxn.setPreemptable(false);
            try {
                /* Lock LSN.  Can discard a NULL_LSN entry without locking. */
                final long lsn = getLsn(i);
                if (lsn != DbLsn.NULL_LSN) {
                    final LockResult lockRet = lockingTxn.nonBlockingLock
                        (lsn, LockType.READ, false /*jumpAheadOfWaiters*/, db);
                    if (lockRet.getLockGrant() == LockGrantType.DENIED) {
                        anyLocksDenied = true;
                        continue;
                    }
                }

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

                    /*
                     * We're about to remove the entry with the idKey so the
                     * node will need a new idkey.
                     */
                    setNewIdKey = true;
                   
                    /*
                     * We think identifier keys are always in the first slot.
                     * However, this assertion fails in DatabaseTest.  Needs
                     * futher investigation.
                     */
                    //assert (i == 0) : i;
                }

                if (db.isDeferredWriteMode()) {
                    final LN ln = (LN) getTarget(i);
                    if (ln != null &&
                        ln.isDirty() &&
                        !DbLsn.isTransient(lsn)) {
                        if (db.isTemporary()) {

                            /*
                             * When a previously logged LN in a temporary DB is
                             * dirty, we can count the LSN of the last logged
                             * LN as obsolete without logging.  There it no
                             * requirement for the dirty deleted LN to be
                             * durable past recovery.  There is no danger of
                             * the last logged LN being accessed again (after
                             * log cleaning, for example), since temporary DBs
                             * do not survive recovery.
                             */
                            if (localTracker != null) {
                                localTracker.countObsoleteNode
                                    (lsn, ln.getGenericLogType(),
                                     ln.getLastLoggedSize(), db);
                            } else {
                                envImpl.getLogManager().countObsoleteNode
                                    (lsn, ln.getGenericLogType(),
                                     ln.getLastLoggedSize(), db,
                                     true /*countExact*/);
                            }
                        } else {

                            /*
                             * When a previously logged deferred-write LN is
                             * dirty, we log the dirty deleted LN to make the
                             * deletion durable.  The act of logging will also
                             * count the last logged LSN as obsolete.
                             */
                            logDirtyLN(i, ln, false /*ensureDurableLsn*/);
                        }
                    }
                }

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

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

        if (getNEntries() != 0 && setNewIdKey) {
            setIdentifierKey(getKey(0));
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;
        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 read lock on the original log LSN.  If this
             * fails, then the original LSN is still write-locked.  We may have
             * to lock again, if the LSN has changed in the BIN, but this
             * initial check prevents a Btree lookup in some cases.
             */
            locker = BasicLocker.createBasicLocker(env, false /*noWait*/);
            /* Don't allow this short-lived lock to be preempted/stolen. */
            locker.setPreemptable(false);
            LockResult lockRet =
                locker.nonBlockingLock(originalLsn, LockType.READ,
                                       false /*jumpAheadOfWaiters*/, 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.
             */
            parentFound = tree.getParentBINForChildLN
                (location, key, false /*splitsAllowed*/,
                 true /*findDeletedEntries*/, UPDATE_GENERATION);
            bin = location.bin;
            int index = location.index;

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

            /* Migrate an LN. */
            processedHere = false;
            migrateLN
                (db, bin.getLsn(index), bin, index,
                 true,           // wasCleaned
                 true,           // isPending
                 originalLsn,
                 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 (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

        startupTracker.start(Phase.REMOVE_TEMP_DBS);
        startupTracker.setProgress(RecoveryProgress.REMOVE_TEMP_DBS);
        Counter counter = startupTracker.getCounter(Phase.REMOVE_TEMP_DBS);
       
        DbTree dbMapTree = envImpl.getDbTree();
        BasicLocker locker =
            BasicLocker.createBasicLocker(envImpl, false /*noWait*/);
        boolean operationOk = false;
        try {
            Iterator<DatabaseId> removeDbs = tempDbIds.iterator();
            while (removeDbs.hasNext()) {
                counter.incNumRead();
                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 {
                            counter.incNumProcessed();
                            envImpl.getDbTree().dbRemove(locker,
                                                         db.getName(),
                                                         db.getId());
                        } catch (DatabaseNotFoundException e) {
                            throw EnvironmentFailureException.
                                unexpectedException(e);
                        }
                    } else {
                        counter.incNumDeleted();
                    }
                }
            }
            operationOk = true;
        } catch (Error E) {
            envImpl.invalidate(E);
            throw E;
        } finally {
            locker.operationEnd(operationOk);
            startupTracker.stop(Phase.REMOVE_TEMP_DBS);

        }
    }
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 = ln.getNodeId();
        BasicLocker locker = null;
        BIN bin = null;
        DIN parentDIN = null;      // for DupCountLNs
        try {
            nLNsCleanedThisRun++;

            /* The whole database is gone, so this LN is obsolete. */
            if (db == null || db.getIsDeleted()) {
                nLNsDeadThisRun++;
                completed = true;
                return;
            }

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

            /*
       * Search down to the bottom most level for the parent of this LN.
       */
            boolean parentFound = tree.getParentBINForChildLN
                (location, key, dupKey, ln,
                 false,  // splitsAllowed
                 true,   // findDeletedEntries
                 false,  // searchDupTree
                 false); // updateGeneration
            bin = location.bin;
            int index = location.index;

            if (!parentFound) {
                nLNsDeadThisRun++;
                completed = true;
    return;
            }

      /*
       * Now we're at the parent for this LN, whether BIN, DBIN or DIN.
       * If knownDeleted, LN is deleted and can be purged.
       */
      if (bin.isEntryKnownDeleted(index)) {
    nLNsDeadThisRun++;
    obsolete = true;
    completed = true;
                return;
      }

            /*
             * Determine whether the parent is the current BIN, or in the case
             * of a DupCountLN, a DIN.  Get the tree LSN in either case.
             */
            boolean lnIsDupCountLN = ln.containsDuplicates();
            long treeLsn;
      if (lnIsDupCountLN) {
    parentDIN = (DIN) bin.fetchTarget(index);
    parentDIN.latch(false);
                ChildReference dclRef = parentDIN.getDupCountLNRef();
                treeLsn = dclRef.getLsn();
      } else {
                treeLsn = bin.getLsn(index);
      }

      /*
             * Check to see whether the LN being migrated is locked elsewhere.
             * Do that by attempting to lock it.  We can hold the latch on the
             * BIN (and DIN) since we always attempt to acquire a non-blocking
             * read lock.  Holding the latch ensures that the INs won't change
             * underneath us because of splits or eviction.
       */
      locker = new BasicLocker(env);
      LockGrantType lock = locker.nonBlockingReadLock(nodeId, db);
      if (lock == LockGrantType.DENIED) {

    /*
     * LN is currently locked by another Locker, so we can't assume
      * anything about the value of the LSN in the bin.  However,
                 * we can check whether the lock owner's abort LSN is greater
                 * than the log LSN; if so, the log LSN is obsolete.  Before
                 * doing this we must release all latches to avoid a deadlock.
     */
                if (parentDIN != null) {
                    parentDIN.releaseLatch();
                    parentDIN = null;
                }
                bin.releaseLatch();
    long abortLsn = locker.getOwnerAbortLsn(nodeId);
    if (abortLsn != DbLsn.NULL_LSN &&
        DbLsn.compareTo(abortLsn, logLsn) > 0) {
        nLNsDeadThisRun++;
        obsolete = true;
    } else {
        nLNsLockedThisRun++;
                    lockDenied = true;
    }
                completed = true;
                return;
      }

      /*
       * We were able to lock this LN in the tree.  Try to migrate this
       * LN to the end of the log file so we can throw away the old log
       * entry.
             *
             * 1. If the LSN in the tree and in the log are the same,
             * we can migrate it, or discard it if the LN is deleted.
             *
             * 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.
             */
            if (treeLsn == logLsn) {
                if (ln.isDeleted()) {

                    /*
                     * If the LN is deleted, we must set knownDeleted to
                     * prevent fetching it later.  This could occur when
                     * scanning over deleted entries that have not been
                     * compressed away [10553].
                     */
                    assert !lnIsDupCountLN;
                    bin.setKnownDeletedLeaveTarget(index);
                    nLNsDeadThisRun++;
                    obsolete = true;
                } else {
                    if (lnIsDupCountLN) {

                        /*
                         * Migrate the DupCountLN now to avoid having to
                         * process the migrate flag for DupCountLNs in all
                         * other places.
                         */
                        long newLNLsn = ln.log
                            (env, db.getId(), key, logLsn, locker);

                        parentDIN.updateDupCountLNRef(newLNLsn);
                        nLNsMigratedThisRun++;
                    } else {

                        /*
                         * Set the migrate flag and dirty the BIN.  The evictor
                         * or checkpointer will migrate the LN later.
                         */
                        bin.setMigrate(index, true);

                        /*
                         * 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();

                        /*
                         * Set the target node so it does not have to be
                         * fetched when it is migrated. Must call postFetchInit
                         * to initialize MapLNs that have not been fully
       * initialized yet [#13191].
                         */
                        if (bin.getTarget(index) == null) {
           ln.postFetchInit(db, logLsn);
                            bin.updateEntry(index, ln);
                        }

                        nLNsMarkedThisRun++;
                    }
                    migrated = true;
                }
            } else {
                /* LN is obsolete and can be purged. */
                nLNsDeadThisRun++;
                obsolete = true;
            }
            completed = true;
            return;
        } finally {
            if (parentDIN != null) {
                parentDIN.releaseLatchIfOwner();
            }

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

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

            if (completed && lockDenied) {
                fileSelector.addPendingLN(ln, db.getId(), key, dupKey);
            }
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;
        try {
            nPendingLNsProcessed++;

            /* The whole database is gone, so this LN is obsolete. */
            if (db == null || db.getIsDeleted()) {
                nLNsDead++;
                obsolete = true;
                completed = true;
                return;
            }

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

            /* Get a non-blocking lock on the original node ID. */
      locker = new BasicLocker(env);
      if (locker.nonBlockingReadLock(ln.getNodeId(), db) ==
                LockGrantType.DENIED) {
                /* Try again later. */
                nPendingLNsLocked++;
                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
                 false); // updateGeneration
            bin = location.bin;
            int index = location.index;

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

            migrateLN
                (db, bin.getLsn(index), bin, index,
                 true,           // wasCleaned
                 true,           // isPending
                 ln.getNodeId(), // lockedPendingNodeId
                 CLEAN_PENDING_LN);
            processedHere = false;
            completed = true;
  } catch (DatabaseException DBE) {
      DBE.printStackTrace();
      Tracer.trace(env, "com.sleepycat.je.cleaner.Cleaner", "processLN",
       "Exception thrown: ", DBE);
      throw DBE;
        } finally {
            if (bin != null) {
                bin.releaseLatchIfOwner();
            }

            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;
        DIN parentDIN = null;      // for DupCountLNs

        try {

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

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

            /* Determine whether this is a DupCountLN or a regular LN. */
            boolean lnIsDupCountLN = node.containsDuplicates();
      if (lnIsDupCountLN) {
    parentDIN = (DIN) node;
    parentDIN.latch(false);
                ChildReference dclRef = parentDIN.getDupCountLNRef();
                lsn = dclRef.getLsn();
                ln = (LN) dclRef.fetchTarget(db, parentDIN);
            } else {
                ln = (LN) node;
            }

            /*
             * 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 = new BasicLocker(env);
                LockGrantType lock = locker.nonBlockingReadLock
                    (ln.getNodeId(), db);
                if (lock == 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++;
                    }
                    lockDenied = true;
                    completed = true;
                    return;
                }
            }

      /* Don't migrate deleted LNs.  */
            if (ln.isDeleted()) {
                assert !lnIsDupCountLN;
                bin.setKnownDeletedLeaveTarget(index);
                if (wasCleaned) {
                    nLNsDead++;
                }
                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.  Although redundant with
             * isFileCleaningInProgress, check toBeCleanedFiles first because
             * it is unsynchronized.
             */
            Long fileNum = new Long(DbLsn.getFileNumber(lsn));
            if (!toBeCleanedFiles.contains(fileNum) &&
                !fileSelector.isFileCleaningInProgress(fileNum)) {
                completed = true;
                if (wasCleaned) {
                    nLNsDead++;
                }
                return;
            }

            /* Migrate the LN. */
            byte[] key = getLNMainKey(bin, index);
            long newLNLsn = ln.log(env, db.getId(), key, lsn, locker);
      if (lnIsDupCountLN) {
                parentDIN.updateDupCountLNRef(newLNLsn);
            } else {
                bin.updateEntry(index, newLNLsn);
            }
            nLNsMigrated++;
            migrated = true;
            completed = true;
            return;
        } finally {
            if (parentDIN != null) {
                parentDIN.releaseLatchIfOwner();
            }

            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.
                 */
                if (bin.getMigrate(index) && (!completed || lockDenied)) {

                    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 (!isRunning()) {
                        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.updateEntry(index, null);
            }

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

            trace(detailedTraceLevel, cleanAction, ln, lsn,
                  completed, obsolete, migrated);
        }
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.