@Override
    public final void alarm(Object obj)
    {
        if (messagingEngine != null)
            SibTr.push(messagingEngine);

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.entry(this, tc, "alarm", "deliveryDelayIndexSize=" + deliveryDelayIndex.size());

        synchronized (lockObject)
        {
            // we try ensure there is only ever 1 alarm thread running and check at the end of each alarm 
            // if another needs scheduling.  3 consecutive checked exceptions are tolerated.
            alarmScheduled = false;

            while (alarming)
            {
                // this is only now possible with a highly unlikely thread scheduling, but cope with it
                // anyway.
                try
                {
                    lockObject.wait();
                } catch (InterruptedException e)
                {
                    // No FFDC Code Needed
                }
            }

            alarming = true;
        }

        LocalTransaction transaction = null;
        int indexUsed = 0;
        long processed = 0;
        long unlocked = 0;
        long cleaned = 0;
        long gone = 0;
        long remain = 0;

        try
        {
            // Once every 5 cycles, set the flag to initiate full-index scan
            // for items which are no longer in the store.
            countForCleanup++;
            if (countForCleanup >= cleanupLimit)
            {
                countForCleanup = 0;
                cleanupDeletedItems = true;
            }
            else
            {
                cleanupDeletedItems = false;
            }

            // Get current system time for start of cycle
            maximumTime = System.currentTimeMillis();
            indexUsed = saveStartTime(maximumTime);

            // Get the first entry from the index and start the cycle
            DeliveryDelayableReference deliveryDelayableRef = null;
            synchronized (lockObject)
            {
                // Point to the start of the tree                  
                deliveryDelayIndex.resetIterator();
                deliveryDelayableRef = deliveryDelayIndex.next();
            }
            while (runEnabled && deliveryDelayableRef != null && deliveryDelayableRef.getDeliveryDelayTime() <= maximumTime)
            {
                processed++;

                DeliveryDelayable deliveryDelayable = (DeliveryDelayable) deliveryDelayableRef.get();
                // If the soft reference is null or if the item indicates that it has
                // already gone from the store, then remove the DeliveryDelayable ref from the index 
                if (deliveryDelayable != null && deliveryDelayable.deliveryDelayableIsInStore())
                {
                    // Now processing items which are either at or past their delivery delay time.
                    // Create a transaction if we don't have one already
                    if (transaction == null)
                    {
                        transaction = messageStore.getTransactionFactory().createLocalTransaction();
                    }
                    // Tell the DeliveryDelayable to unlock. If it returns true, then remove it from the DeliveryDelay index.
                    if (deliveryDelayable.deliveryDelayableUnlock((PersistentTransaction) transaction, AbstractItem.DELIVERY_DELAY_LOCK_ID))
                    {
                        unlocked++;
                        // Remove from DeliveryDelay index
                        remove(deliveryDelayableRef, true);
                        batchCount++;
                        if (batchCount >= BATCH_SIZE)
                        {
                            transaction.commit();
                            transaction = null;
                            batchCount = 0;
                        }
                    }
                    else
                    {
                        remain++;
                    }
                }
                else
                {
                    if (remove(deliveryDelayableRef, false))
                    {
                        gone++;
                    }
                }
                synchronized (lockObject)
                {
                    deliveryDelayableRef = deliveryDelayIndex.next();
                }
            }

            // Once every 'n' cycles, continue to the end of the DeliveryDelay index
            // removing any entries for items which are no longer in the store.
            if (cleanupDeletedItems)
            {
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                    SibTr.debug(this, tc, "DeliveryDelayManager cleanup in progress");

                while (runEnabled && deliveryDelayableRef != null)
                {
                    DeliveryDelayable deliveryDelayable = (DeliveryDelayable) deliveryDelayableRef.get();
                    // If the soft reference is null or if the item indicates that it has
                    // gone from the store, then remove the DeliveryDelayable ref from the index 
                    if (deliveryDelayable == null || !(deliveryDelayable.deliveryDelayableIsInStore()))
                    {
                        if (remove(deliveryDelayableRef, false))
                        {
                            cleaned++;
                        }
                    }
                    synchronized (lockObject)
                    {
                        deliveryDelayableRef = deliveryDelayIndex.next();
                    }
                }
                // Check how much useful work we did, and vary the frequency 
                // of the cleanup cycle. 
                if (cleaned < 10 && cleanupLimit < 100)
                {
                    cleanupLimit += CLEANUP_EVERY_N_CYCLES; // Slow down
                }
                else if (cleaned > 1000 && cleanupLimit > CLEANUP_EVERY_N_CYCLES)
                {
                    cleanupLimit = CLEANUP_EVERY_N_CYCLES; // Restore default
                }
                else if (cleaned > 100 && cleanupLimit > CLEANUP_EVERY_N_CYCLES)
                {
                    cleanupLimit -= CLEANUP_EVERY_N_CYCLES; // Speed up
                }
            }

            if (transaction != null) // Did we create a transaction?
            {
                if (batchCount == 0) // No work outstanding  
                {
                    transaction.rollback();
                }
                else // Work outstanding, must be committed  
                {
                    transaction.commit();
                    batchCount = 0;
                }
                transaction = null;
            }
            consecutiveFailures = 0;
        } // end try
        catch (Exception e)
        {
            com.ibm.ws.ffdc.FFDCFilter.processException(e, "com.ibm.ws.sib.msgstore.deliverydelay.DeliveryDelayManager.alarm", "550", this);
            if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                SibTr.event(this, tc, "alarm", "DeliveryDelayManager thread exception: " + e);

            consecutiveFailures++;
            lastException = e;
            lastExceptionTime = timeNow();

            if (consecutiveFailures > MAX_CONSECUTIVE_FAILURES)
            {
                synchronized (lockObject)
                {
                    runEnabled = false;
                    addEnabled = false;
                }

                if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                    SibTr.exit(tc, "alarm", e);
                throw new MessageStoreRuntimeException("DELIVERYDELAYMANAGER_DAEMON_TERMINATED_SIMS2011", new Object[] { e }, e);
            }
        } finally
        {
            long currIndexSize = 0;
            // Synchronize while we decide whether to schedule another alarm or not
            synchronized (lockObject)
            {
                alarming = false;
                currIndexSize = deliveryDelayIndex.size();

                if (runEnabled) // We have not been told to stop,
                {
                    if (currIndexSize > 0) // and the index is not empty, 
                    {
                        scheduleAlarm(interval); // ... schedule the next alarm
                    }
                }
                else // DeliveryDelayManager is stopping
                {
                    // Disallow addition of any further DeliveryDelayable to the index.
                    addEnabled = false;
                }
                lockObject.notifyAll();
            }

            // Save statistics for diagnostic dump using the same log index as
            // returned by saveStartTime() called at start of this cycle.
            logIndexSize[indexUsed] = currIndexSize;
            logProcessed[indexUsed] = processed;
            logUnlocked[indexUsed] = unlocked;
            logGone[indexUsed] = gone;
            logRemain[indexUsed] = remain;
            logCleaned[indexUsed] = cleaned;

        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.exit(tc,
                       "alarm",
                       " processed=" + processed + " gone=" + gone + " unlocked=" + unlocked + " remain=" + remain + " cleaned=" + cleaned + " DeliveryDelayIndexSize="
                                       + deliveryDelayIndex.size()
                                       + " cleanupLimit="
                                       + cleanupLimit + " alarmScheduled=" + alarmScheduled);

        if (messagingEngine != null)
            SibTr.pop();
    }
@ Override public final void alarm ( Object obj ) { if ( messagingEngine != null ) SibTr . push ( messagingEngine ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . entry ( this , tc , "alarm" , "deliveryDelayIndexSize=" + deliveryDelayIndex . size ( ) ) ; synchronized ( lockObject ) { alarmScheduled = false ; while ( alarming ) { try { lockObject . wait ( ) ; } catch ( InterruptedException e ) { } } alarming = true ; } LocalTransaction transaction = null ; int indexUsed = 0 ; long processed = 0 ; long unlocked = 0 ; long cleaned = 0 ; long gone = 0 ; long remain = 0 ; try { countForCleanup ++ ; if ( countForCleanup >= cleanupLimit ) { countForCleanup = 0 ; cleanupDeletedItems = true ; } else { cleanupDeletedItems = false ; } maximumTime = System . currentTimeMillis ( ) ; indexUsed = saveStartTime ( maximumTime ) ; DeliveryDelayableReference deliveryDelayableRef = null ; synchronized ( lockObject ) { deliveryDelayIndex . resetIterator ( ) ; deliveryDelayableRef = deliveryDelayIndex . next ( ) ; } while ( runEnabled && deliveryDelayableRef != null && deliveryDelayableRef . getDeliveryDelayTime ( ) <= maximumTime ) { processed ++ ; DeliveryDelayable deliveryDelayable = ( DeliveryDelayable ) deliveryDelayableRef . get ( ) ; if ( deliveryDelayable != null && deliveryDelayable . deliveryDelayableIsInStore ( ) ) { if ( transaction == null ) { transaction = messageStore . getTransactionFactory ( ) . createLocalTransaction ( ) ; } if ( deliveryDelayable . deliveryDelayableUnlock ( ( PersistentTransaction ) transaction , AbstractItem . DELIVERY_DELAY_LOCK_ID ) ) { unlocked ++ ; remove ( deliveryDelayableRef , true ) ; batchCount ++ ; if ( batchCount >= BATCH_SIZE ) { transaction . commit ( ) ; transaction = null ; batchCount = 0 ; } } else { remain ++ ; } } else { if ( remove ( deliveryDelayableRef , false ) ) { gone ++ ; } } synchronized ( lockObject ) { deliveryDelayableRef = deliveryDelayIndex . next ( ) ; } } if ( cleanupDeletedItems ) { if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "DeliveryDelayManager cleanup in progress" ) ; while ( runEnabled && deliveryDelayableRef != null ) { DeliveryDelayable deliveryDelayable = ( DeliveryDelayable ) deliveryDelayableRef . get ( ) ; if ( deliveryDelayable == null || ! ( deliveryDelayable . deliveryDelayableIsInStore ( ) ) ) { if ( remove ( deliveryDelayableRef , false ) ) { cleaned ++ ; } } synchronized ( lockObject ) { deliveryDelayableRef = deliveryDelayIndex . next ( ) ; } } if ( cleaned < 10 && cleanupLimit < 100 ) { cleanupLimit += CLEANUP_EVERY_N_CYCLES ; } else if ( cleaned > 1000 && cleanupLimit > CLEANUP_EVERY_N_CYCLES ) { cleanupLimit = CLEANUP_EVERY_N_CYCLES ; } else if ( cleaned > 100 && cleanupLimit > CLEANUP_EVERY_N_CYCLES ) { cleanupLimit -= CLEANUP_EVERY_N_CYCLES ; } } if ( transaction != null ) { if ( batchCount == 0 ) { transaction . rollback ( ) ; } else { transaction . commit ( ) ; batchCount = 0 ; } transaction = null ; } consecutiveFailures = 0 ; } catch ( Exception e ) { com . ibm . ws . ffdc . FFDCFilter . processException ( e , "com.ibm.ws.sib.msgstore.deliverydelay.DeliveryDelayManager.alarm" , "550" , this ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . event ( this , tc , "alarm" , "DeliveryDelayManager thread exception: " + e ) ; consecutiveFailures ++ ; lastException = e ; lastExceptionTime = timeNow ( ) ; if ( consecutiveFailures > MAX_CONSECUTIVE_FAILURES ) { synchronized ( lockObject ) { runEnabled = false ; addEnabled = false ; } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . exit ( tc , "alarm" , e ) ; throw new MessageStoreRuntimeException ( "DELIVERYDELAYMANAGER_DAEMON_TERMINATED_SIMS2011" , new Object [ ] { e } , e ) ; } } finally { long currIndexSize = 0 ; synchronized ( lockObject ) { alarming = false ; currIndexSize = deliveryDelayIndex . size ( ) ; if ( runEnabled ) { if ( currIndexSize > 0 ) { scheduleAlarm ( interval ) ; } } else { addEnabled = false ; } lockObject . notifyAll ( ) ; } logIndexSize [ indexUsed ] = currIndexSize ; logProcessed [ indexUsed ] = processed ; logUnlocked [ indexUsed ] = unlocked ; logGone [ indexUsed ] = gone ; logRemain [ indexUsed ] = remain ; logCleaned [ indexUsed ] = cleaned ; } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . exit ( tc , "alarm" , " processed=" + processed + " gone=" + gone + " unlocked=" + unlocked + " remain=" + remain + " cleaned=" + cleaned + " DeliveryDelayIndexSize=" + deliveryDelayIndex . size ( ) + " cleanupLimit=" + cleanupLimit + " alarmScheduled=" + alarmScheduled ) ; if ( messagingEngine != null ) SibTr . pop ( ) ; }
Process the delivery delay index.

This will process the delivery delay index in sequence of delivery delay time up to the
current time. Any entries which have passed their delivery delay time will be called
to unlock itself. If they return true, their references will be removed from the index,
otherwise their references will remain and be processed again on subsequent cycles.

This method is triggered by the AlarmManager. On completion, it schedules the
next alarm, unless stop() has been called or the index is empty.

@throws SevereMessageStoreException