docs: protected void add(ManagedObject managedObject,
                         Transaction transaction,
                         long logSpaceReservedDelta)
                      throws ObjectManagerException {
          final String methodName = "add";
          if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
              trace.entry(this, cclass, methodName, new Object[] { managedObject,
                                                                  transaction,
                                                                  new Long(logSpaceReservedDelta) });
  
          // We should not call ManagedObject add/delete/replace etc methods with the transaction lock held
          // because some of these call transaction.lock() which might wait(), thus stalling the checkpoint
          // as it tries to get the transaction lock.
          // Make the ManagedObject ready for an addition,
          // give it a chance to blow up in anything is wrong. If it turns out that this is the wrong transaction 
          // we will call postAdd after we have taken the lock on this transaction.
          managedObject.preAdd(transaction);
  
          // Changes may be made to these objects after this point, however they will not be restored,
          // we record the object at this point in time.
          // We have to allow for some other transaction to modify the object between the end of this transaction and
          // when we actually write it to the ObjectStore, using optimisticReplace.
          // We address this by keeping a copy of the serialised immage of the object when we create the
          // log record along with the logSequenceNumber when we write it.
          // A higher level lock, such as synchronizing on LinkedList must protect against our capturing the wrong
          // serialized version of the ManagedObject.
          // We do not add the ManagedObject to the ObjectStore now because the ObjectStore might force it to disk
          // before we force the log. This would leave us with no way of recovering if we crashed in that state.
          // We get the serializedBytes before taking the lock on the transaction bacause any stall in the 
          // ObjectStore.reserve() call would block the checkpoint.
          ObjectManagerByteArrayOutputStream serializedBytes = null;
          try {
              if (managedObject.owningToken.getObjectStore().getUsesSerializedForm())
                  serializedBytes = managedObject.getSerializedBytes();
          } catch (ObjectManagerException exception) {
              // No FFDC Code Needed.
              // Drive the postAdd method for the object.
              managedObject.postAdd(transaction, false);
  
              if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
                  trace.exit(this, cclass, methodName, new Object[] { exception });
              throw exception;
          } // try...
  
          synchronized (this) {
              // To defend against two application threads completing the same transaction and trying to
              // continue with it at the same time we check that the Transaction still refers to this one,
              // now that we are synchronized on the InternalTransaction.
              if (transaction.internalTransaction != this) {
                  managedObject.postAdd(transaction, false);
  
                  if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
                      trace.exit(this, cclass, methodName, new Object[] { "via InvalidTransactionException",
                                                                         transaction.internalTransaction });
                  // Same behaviour as if the transaction was completed and replaced by
                  // objectManagerState.dummyInternalTransaction.
                  throw new InvalidStateException(this,
                                                  InternalTransaction.stateTerminated,
                                                  InternalTransaction.stateNames[InternalTransaction.stateTerminated]);
  
              } // if (transaction.internalTransaction != this).
  
              // Is data logging required for this object in order too recover it?
              // Non persistent objects that are within the scope of the transaction do not
              // require logging. This is because we reconstruct their state from other
              // objects at restart or because their state is restablished at restart in some other way,
              // for example, we might delete them on restart.
              // We write the log record now but dont actually write to the ObjectStore until
              // the transaction has commited. The actual ObjectStore write to disk happens even
              // later when the object store is flushed.
              long logSequenceNumber;
  
              // This try block catches any fatal error that causes us to fail to write the transaction
              // log or reserve space in the Objectstores.
              try {
                  if (managedObject.owningToken.getObjectStore().getPersistence()) {
                      testState(nextStateForInvolvePersistentObject);
  
                      logSpaceReservedDelta = logSpaceReservedDelta + Token.maximumSerializedSize();
                      if (logSpaceReserved == 0)
                          logSpaceReservedDelta = logSpaceReservedDelta + logSpaceReservedOverhead;
  
                      TransactionAddLogRecord transactionAddLogRecord = new TransactionAddLogRecord(this,
                                                                                                    managedObject.owningToken,
                                                                                                    serializedBytes);
  
                      // If we throw an exception in here no state change has been done.
                      logSequenceNumber = objectManagerState.logOutput.writeNext(transactionAddLogRecord, logSpaceReservedDelta,
                                                                                 true, false);
                      setState(nextStateForInvolvePersistentObject); // Make the state change.
  
                      logSpaceReserved = logSpaceReserved + logSpaceReservedDelta;
                      // Remember what we logged in case we commit this version of the ManagedObject.
                      loggedSerializedBytes.put(managedObject.owningToken, serializedBytes);
  
                  } else { // if (tokenToAdd.getObjectstore().getPersistence()).
                      setState(nextStateForInvolveNonPersistentObject); // Make the state change.
                      logSequenceNumber = objectManagerState.getDummyLogSequenceNumber();
  
                      // Do we need to capture the serialized form of the ManagedObject for the ObjectStore?
                      if (managedObject.owningToken.getObjectStore().getUsesSerializedForm()) {
                          // Remember what we would have logged in case we commit this version of the ManagedObject.
                          loggedSerializedBytes.put(managedObject.owningToken,
                                                    serializedBytes);
                      } // if (managedObject.owningToken.getObjectStore().getUsesSerializedForm()).
                  } // If Non Persistent.
              } catch (ObjectManagerException exception) {
                  // The write was not done.
                  // No FFDC Code Needed.
                  ObjectManager.ffdc.processException(this, cclass, methodName, exception, "1:860:1.41");
  
                  // Drive the postadd method for the object.
                  managedObject.postAdd(transaction, false);
  
                  if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
                      trace.exit(this, cclass, methodName, new Object[] { exception });
                  throw exception;
              } // try...
  
              // The ManagedObject is now included in the transaction.
              includedManagedObjects.put(managedObject.owningToken, managedObject);
              // Remember which logSequenceNumber was used when we logged the ManagedObject.
              logSequenceNumbers.put(managedObject.owningToken,
                                     new Long(logSequenceNumber));
              managedObjectSequenceNumbers.put(managedObject.owningToken,
                                               new Long(managedObject.getUpdateSequence()));
          } // synchronized (this).
  
          // Drive the postAdd method for the object.
          managedObject.postAdd(transaction, true);
  
          if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
              trace.exit(this, cclass, methodName);
      }