docs: private CreateTOMs recoverFromPersistentState(AIProtocolItemStream persStreamState)
      throws MessageStoreException
    {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        SibTr.entry(tc, "recoverFromPersistentState", persStreamState);
  
      NonLockingCursor cursor = null;
  
      // ticks may still be locked by a transaction that did not commit before failure
      AbstractItem abitem = null;
      ArrayList<AIAcceptedTick> acceptedTicks = null;
      ArrayList<AIRejectedRange> rejectedTicks = null;
      ArrayList<AIRequestedTick> requestedTicks = null;
      long completedPrefix = 0;
  
      try
      {
        cursor = persStreamState.newNonLockingItemCursor(null);
        cursor.allowUnavailableItems();
        while ((abitem = cursor.next()) != null)
        {
          if (abitem instanceof AIProtocolItem)
          {
            AIProtocolItem protocolItem = (AIProtocolItem) abitem;
            byte protocolState = protocolItem.getProtocolState();
  
            if (protocolState == TickRange.Accepted)
            {
              // We expect all accepted items to be before our completed
              // prefix, as they are removed from the stream as the prefix
              // is updated.
              if (protocolItem.getTick() > completedPrefix)
              {
                protocolItem.setAIHCallbackTarget(_parent);
                persStreamState.setCurrentTransaction(protocolItem, false);
                if (protocolItem.isAvailable())
                {
                  AIAcceptedTick at = null;
                  try
                  {
                    at = writeAcceptedNoTimeout(protocolItem.getTick());
                  }
                  catch(SIErrorException e)
                  {
                    //see defect 273949:
                    //invalid stream state transitions have been observed in this path.
                    //The errors are not repeatable, and have not been diagnosed.
                    //The symptom is that the code attempts to modify ticks into 'accepted' state
                    //when they are already 'completed'.
                    //It is possible that this is caused when AIProtocolItem objects are stored
                    //as STORE_EVENTUALLY while AICompletedPrefixItem objects are stored as STORE_ALWAYS.
                    //This FFDC has been added in order to capture enough information if this
                    //error is observed again.
                    FFDCFilter.processException(
                      e,
                      "com.ibm.ws.sib.processor.gd.AIStream.recoverFromPersistentState",
                      "1:1636:1.108.2.18",
                      new Object[]{
                        Long.valueOf(this.getCompletedPrefix()),
                        Long.valueOf(protocolItem.getTick()),
                        protocolItem,
                        persStreamState,
                        _targetStream,
                        this
                      });
                    if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "recoverFromPersistentState", e);
                    throw e;
                  }
                  if (acceptedTicks == null)
                  {
                    acceptedTicks = new ArrayList<AIAcceptedTick>();
                  }
                  acceptedTicks.add(at);
                  // build the index as we go
                  synchronized(_completedPrefix)
                  {
                    _itemStreamIndex.add(protocolItem);
                  }
                }
                else
                {
                  // set tick back to V/U, but have no data message!
                  long tick = protocolItem.getTick();
                  AIValueTick valueTick =
                    new AIValueTick(tick, Reliability.ASSURED_PERSISTENT);
                  TickRange valueRange = new TickRange(TickRange.Value, tick, tick);
                  valueRange.value = valueTick;
                  valueRange.valuestamp = tick;
                  _targetStream.writeRange(valueRange);
                  protocolItem.setUnavailableAfterRecovery(true);
                }
              }
              // PK75049 Accepted items before the completed prefix in our
              // persistent state are a result of a rollback while removing thems.
              // See CompletedPrefixAsyncUpdate for details.
              else
              {
                // We need to cleanup these redundant entries.
                // This prevents problems if we later attempt to delete the stream.
                SIMPTransactionManager txMan = _mp.getTXManager();
                LocalTransaction mpTxn = txMan.createLocalTransaction(false);
                try {
                  Transaction msTxn = txMan.resolveAndEnlistMsgStoreTransaction(mpTxn);
                  // No need to lock the item first as we haven't completed GD recovery yet
                  protocolItem.remove(msTxn, Item.NO_LOCK_ID);
                  mpTxn.commit();
                }
                catch (Exception e) {
                  // FFDC and continue. The state will remain.
                  FFDCFilter.processException(
                      e,
                      "com.ibm.ws.sib.processor.gd.AIStream.recoverFromPersistentState",
                      "1:1693:1.108.2.18",
                      this);
                }
              }
            }
            else
            {
              // there only should be accepted items as we are not persisting completed items
              // FFDC to log the issue (which could prevent deletion of the stream) and continue.
              SIErrorException e = new SIErrorException();              
              FFDCFilter.processException(
                  e,
                  "com.ibm.ws.sib.processor.gd.AIStream.recoverFromPersistentState",
                  "1:1706:1.108.2.18",
                  this);
            }
          }
          else if (abitem instanceof AICompletedPrefixItem)
          {
            // A completed prefix item is always available, since it is always processed in the context of a local tran
            _completedPrefix = (AICompletedPrefixItem) abitem;
            long startTick = 0;
            completedPrefix = _completedPrefix.getTick();
            writeCompletedRange(startTick, completedPrefix);
            _targetStream.setCompletedPrefix(completedPrefix);
          }
        }
      }
      finally
      {
        if (cursor != null)
          cursor.finished();
      }
  
      // SIB0113
      // Now fill in the reconstituted AOValue ticks with Requested ranges
      ArrayList<AOValue> values =
        ((AIContainerItemStream)_itemStream.getItemStream()).getAOLinks();
      if (values != null)
      {
        Iterator<AOValue> it = values.iterator();
        while(it.hasNext())
        {
          AOValue val = it.next();
  
          // Set appropriate tick to an Requested value.
          long tick = val.getAIRequestTick();
          TickRange requestRange = new TickRange(TickRange.Requested, tick, tick);
          AIRequestedTick rt = new AIRequestedTick(tick, val, SIMPConstants.INFINITE_TIMEOUT);
          requestRange.value = rt;
          requestRange.valuestamp = tick;
          _targetStream.writeRange(requestRange);
          if (requestedTicks == null)
            requestedTicks = new ArrayList<AIRequestedTick>();
          requestedTicks.add(rt);
        }
      }
  
      // Now fill in gaps with L/R (Rejected ranges)
      long start = _targetStream.getCompletedPrefix() + 1;
      long end = _latestTick;
      _targetStream.setCursor(start);
      TickRange tr2 = null;
      TickRange tr1 = _targetStream.getNext();
      while ((tr1.startstamp <= end) && (tr1 != tr2))
      {
        if (tr1.type == TickRange.Unknown)
        {
          long rangeStart = tr1.startstamp;
          long rangeEnd = ((tr1.endstamp > end) ? end : tr1.endstamp);
          AIRejectedRange rr = writeRejectedNoTimeout(rangeStart, rangeEnd, 0, true);
          if (rejectedTicks == null)
            rejectedTicks = new ArrayList<AIRejectedRange>();
          rejectedTicks.add(rr);
        }
        else if (tr1.type == TickRange.Value)
        {
          // Must have been recovered above, leave it as is
        }
        else if (tr1.type == TickRange.Accepted)
        {
          // Must have been recovered above, leave it as is
        }
        else if (tr1.type == TickRange.Requested)
        {
          // Recovered during IME reconstitute
        }
        else
        {
          // No other types have been recovered
        }
  
        tr2 = tr1;
        tr1 = _targetStream.getNext();
      }
  
      CreateTOMs ct = new CreateTOMs(acceptedTicks, rejectedTicks, requestedTicks);
  
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        SibTr.exit(tc, "recoverFromPersistentState", ct);
  
      return ct;
    }