deletes unused LockedObjects and resets the counter. works recursively
starting at the given LockedObject

@param transaction
@param lo
LockedObject
@param temporary
Clean temporary or real locks

@return if cleaned
557326
private boolean cleanLockedObjects(ITransaction transaction,
            LockedObject lo, boolean temporary) {

        if (lo._children == null) {
            if (lo._owner == null) {
                if (temporary) {
                    lo.removeTempLockedObject();
                } else {
                    lo.removeLockedObject();
                }

                return true;
            } else {
                return false;
            }
        } else {
            boolean canDelete = true;
            int limit = lo._children.length;
            for (int i = 0; i < limit; i++) {
                if (!cleanLockedObjects(transaction, lo._children[i], temporary)) {
                    canDelete = false;
                } else {

                    // because the deleting shifts the array
                    i--;
                    limit--;
                }
            }
            if (canDelete) {
                if (lo._owner == null) {
                    if (temporary) {
                        lo.removeTempLockedObject();
                    } else {
                        lo.removeLockedObject();
                    }
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
416276
@Override
    public void cleanupTransactionBacklogOnRepair() {
        if (m_isLeader && m_sendToHSIds.length > 0) {
            m_mailbox.send(m_sendToHSIds, new MPBacklogFlushMessage());
        }
        Iterator<Entry<Long, TransactionState>> iter = m_outstandingTxns.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<Long, TransactionState> entry = iter.next();
            TransactionState txnState = entry.getValue();
            if (TxnEgo.getPartitionId(entry.getKey()) == MpInitiator.MP_INIT_PID ) {
                if (txnState.isReadOnly()) {
                    txnState.setDone();
                    m_duplicateCounters.entrySet().removeIf((e) -> e.getKey().m_txnId == entry.getKey());
                    iter.remove();
                }
            }
        }

        // flush all RO transactions out of backlog
        m_pendingTasks.removeMPReadTransactions();
    }
979352
protected void unlockAbandonedLock(final String mutexName) {
        this.executeIgnoreRollback(
                new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        final EntityManager entityManager = getEntityManager();
                        final ClusterMutex clusterMutex = getClusterMutex(mutexName);

                        if (!isLockAbandoned(clusterMutex)) {
                            // No longer abandoned
                            return;
                        }

                        logger.warn("Unlocking abandoned " + clusterMutex);
                        clusterMutex.unlock();
                        entityManager.persist(clusterMutex);
                        try {
                            entityManager.flush();
                        } catch (OptimisticLockException e) {
                            logger.trace(
                                    "Abandoned mutex {} was cleared by another thread or server",
                                    mutexName);
                        }
                    }
                });
    }
979155
def clear_transaction(self):
        
        with self._transaction_lock:
            local = self._transaction_local
            if not local.pipes:
                raise ValueError('No transaction is currently active.')
            local.abort()
658306
@Override
    public void afterCompletion(TransactionCommon transaction, boolean committed)
    {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.entry(tc, "afterCompletion", new Object[] { transaction, Boolean.valueOf(committed) });

        synchronized (this)
        {
            // If the connection is already closed this transaction
            // will have been removed.
            if (!_closed)
            {
                synchronized (_ownedTransactions)
                {
                    // Remove the transaction from the connections list
                    _ownedTransactions.remove(transaction);
                }
            }
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.exit(tc, "afterCompletion");
    }
1267721
public function delete( $object, $transaction = self::TRANSACTION_LAST_USED )
    {
        // this'll throw a exception if anything isn't right
        $task = Task::init( $object, Task::DELETE );
        $transaction = $this->getTransaction($transaction,true);
        $this->queue[$transaction][] = $task;
        return $this;
    }
907385
public boolean upgradeLock(TransactionImpl tx, Object obj)
    {
        LockEntry writer = getWriter(obj);
        if (writer == null)
        {
            Collection readers = this.getReaders(obj);
            if (readers.size() == 1)
            {
                LockEntry reader = (LockEntry) readers.iterator().next();
                if (reader.isOwnedBy(tx))
                {
                    if (upgradeLock(reader))
                        return true;
                    else
                        return upgradeLock(tx, obj);
                }
            }
            else if (readers.size() == 0)
            {
                if (setWriter(tx, obj))
                    return true;
                else
                    return upgradeLock(tx, obj);
            }


        }
        else if (writer.isOwnedBy(tx))
        {
            return true;    // If I already have Write, then I've upgraded.
        }

        return false;
    }
371165
protected synchronized void lock(ManagedObject managedObject)
                    throws ObjectManagerException
    {
        throw new InvalidStateException(this, InternalTransaction.stateTerminated, InternalTransaction.stateNames[InternalTransaction.stateTerminated]);
    }
761610
public synchronized void preDelete(Transaction transaction)
                    throws ObjectManagerException
    {
        final String methodName = "preDelete";
        if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
            trace.entry(this, cclass, methodName, new Object[] { transaction });

        // TODO Remove this fix, we should not need it now we do not split checkpoint sets.
        // Defect 326031
        // We only need to do this check once so at recovery time we
        // can rely on it having been done when the transaction first 
        // ran.
        // TODO: Can we avoid this check by grouping transaction work into a single checkpoint?
        // TODO: Re tested this on 18/6/07 and the failure still occurs even though we now write
        // TODO: complete transactions in a checkpoint. Here is a scenarion that might cause this,
        // TODO: however the actual test ( performance) does the delete for the entry and list as two
        //       separate serial tracactions!
        // 
        //   Application Thread          Checkpoint Helper      LogRecords   
        //  
        //   Delete Entry                                       Delete Entry 
        //   Delete List                                        Delete List
        //                               SetRequiresCheckpoint
        // 
        //                               Checkpoint Start       Checkpoint Start. 
        //                                                      Checkpoint Entry(Deleted)
        //                                                      Checkpoint List(Deleted)
        //
        //   Commit                                             Commit
        //   Delete Entry/List from Store
        //                               Flush ObjectStore             
        //                               Checkpoint End         Checkpoint End.  
        // 
        //   
        //   Crash 
        // 
        //   Recover List in Deleted state, 
        //   Entry not yet recovered in deleted state.

        if (transaction.getObjectManagerStateState() != ObjectManagerState.stateReplayingLog) {
            // The list must be empty, apart from links this transaction will delete.
            Token nextToken = head;
            while (nextToken != null) {
                Link nextLink = (Link) nextToken.getManagedObject();
                if (nextLink.willBeDeleted(transaction))
                    nextToken = nextLink.next;
                else {
                    if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
                        trace.exit(this, cclass,
                                   methodName,
                                   "via CollentionNotEmptyException"
                                                   + "size=" + size + "(long)"
                                                   + " nextLink.state=" + nextLink.state + "(int) " + Link.stateNames[nextLink.state]
                                                   + "\n nextLink.getTransactionLock()=" + nextLink.getTransactionLock() + "(transactionLock)"
                                        );

                    throw new CollectionNotEmptyException(this, size, transaction);
                    //System.out.println("LinkedList.preDelete nextLink.state ="+nextLink.state+" "+Link.stateNames[nextLink.state]
                    //                  +"\n nextLink.getTransactionLock()="+nextLink.getTransactionLock() 
                    //                  );
                    //break;
                } // if (  nextLink.state == Link.stateToBeDeleted...
            } // while (nextToken != null).
        } // if not recovering...

        super.preDelete(transaction); // Also takes a lock.
        // Visibility is now restricted to our transaction only.

        if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
            trace.exit(this, cclass, methodName);
    }
495004
protected void eventPostCommitRemove(SIMPMessage msg, TransactionCommon transaction)
    {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.entry(tc, "eventPostCommitRemove", new Object[] { msg, transaction });

        // NB: ideally this would go in afterCompletion but we
        // dont have the transaction reference to register for the callback
        synchronized (orderLock)
        {

            // Remove the transaction from the transactionSet if applicable
            // Use the orderLock to synch with attachConsumer
            if (transactionSet != null)
            {
                transactionSet.remove(transaction.getPersistentTranId());
                if (transactionSet.isEmpty())
                {
                    transactionSet = null;
                    // Get the consumer and resume it
                    consumerPoints.get(0).
                                    getConsumerPoint().
                                    resumeConsumer(DispatchableConsumerPoint.SUSPEND_FLAG_INITIAL_INDOUBTS);
                }
            }
        }

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
            SibTr.exit(tc, "eventPostCommitRemove");
    }
85577
public synchronized boolean checkWrite(TransactionImpl tx, Object obj)
    {
        if (log.isDebugEnabled()) log.debug("LM.checkWrite(tx-" + tx.getGUID() + ", " + new Identity(obj, tx.getBroker()).toString() + ")");
        LockStrategy lockStrategy = LockStrategyFactory.getStrategyFor(obj);
        return lockStrategy.checkWrite(tx, obj);
    }
1255472
public void preDelete(Transaction transaction)
                    throws ObjectManagerException
    {
        if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
            trace.entry(this, cclass,
                        "preDelete",
                        "transaction=" + transaction + "(Transaction)");

        synchronized (headSequenceNumberLock) {
            tailSequenceNumberLock.lock();
            try {
                // Defect 322295
                // We only need to do this check at runtime. At recovery time we can rely on the
                // check been done before the OM went down. Also in some cases the subList array may
                // be padded with nulls depending on how many were successfully deleted from the
                // object store before the OM went down.
                if (transaction.getObjectManagerStateState() != ObjectManagerState.stateReplayingLog) {
                    // Check that the sublists are empty.
                    for (int i = 0; i < subLists.length; i++) {
                        // The list must be empty, apart from links this transaction will delete.
                        Token nextToken = subLists[i].head;
                        while (nextToken != null) {
                            LinkedList.Link nextLink = (LinkedList.Link) nextToken.getManagedObject();
                            if (nextLink.willBeDeleted(transaction))
                                nextToken = nextLink.next;
                            else {
                                if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
                                    trace.exit(this, cclass,
                                               "preDelete",
                                               "via CollentionNotEmptyException"
                                                               + "size()=" + size() + "(long)"
                                                               + " nextLink.state=" + nextLink.state + "(int) " + LinkedList.Link.stateNames[nextLink.state]
                                                               + "\n nextLink.getTransactionLock()=" + nextLink.getTransactionLock() + "(TransactionLock)"
                                                    );

                                throw new CollectionNotEmptyException(this, size(), transaction);
                                //System.out.println("LinkedList.preDelete nextLink.state ="+nextLink.state+" "+LinkedList.Link.stateNames[nextLink.state]
                                //                                                                                              +"\n nextLink.getTransactionLock()="+nextLink.getTransactionLock() 
                                //                                                                                              );
                                //break;
                            } // if (  nextLink.state == Link.stateToBeDeleted...
                        } // while (nextToken != null).

                    } // for subLists.
                } // if not recovering...

                super.preDelete(transaction); // Also takes a lock.
                // Visibility is now restricted to our transaction only.

                // Now delete the sublists. 
                // If we are recovering, the delete of the sublists will have already been done
                // so don't do it again.
                if (transaction.getObjectManagerStateState() != ObjectManagerState.stateReplayingLog) {
                    transaction.optimisticReplace(null, null, java.util.Arrays.asList(subLists), null);
                } // if not recovering...

            } finally {
                if (tailSequenceNumberLock.isHeldByCurrentThread())
                    tailSequenceNumberLock.unlock();
            } // try (tailSequenceNumberLock).
        } // synchronized (headSequenceNumberLock).

        if (Tracing.isAnyTracingEnabled() && trace.isEntryEnabled())
            trace.exit(this, cclass,
                       "preDelete");
    }
1133022
@SuppressWarnings({"OverlyLongMethod"})
    public void clearProperties(@NotNull final PersistentStoreTransaction txn, @NotNull final Entity entity) {
        final Transaction envTxn = txn.getEnvironmentTransaction();
        final PersistentEntityId id = (PersistentEntityId) entity.getId();
        final int entityTypeId = id.getTypeId();
        final long entityLocalId = id.getLocalId();
        final PropertiesTable properties = getPropertiesTable(txn, entityTypeId);
        final PropertyKey propertyKey = new PropertyKey(entityLocalId, 0);
        try (Cursor cursor = getPrimaryPropertyIndexCursor(txn, properties)) {
            for (boolean success = cursor.getSearchKeyRange(PropertyKey.propertyKeyToEntry(propertyKey)) != null;
                 success; success = cursor.getNext()) {
                ByteIterable keyEntry = cursor.getKey();
                final PropertyKey key = PropertyKey.entryToPropertyKey(keyEntry);
                if (key.getEntityLocalId() != entityLocalId) {
                    break;
                }
                final int propertyId = key.getPropertyId();
                final ByteIterable value = cursor.getValue();
                final PropertyValue propValue = propertyTypes.entryToPropertyValue(value);
                txn.propertyChanged(id, propertyId, propValue.getData(), null);
                properties.deleteNoFail(txn, entityLocalId, value, propertyId, propValue.getType());
            }
        }
    }
1355548
public void writeObjects(boolean reuse) throws TransactionAbortedException, LockNotGrantedException
    {
        PersistenceBroker broker = transaction.getBroker();
        ConnectionManagerIF connMan = broker.serviceConnectionManager();
        boolean saveBatchMode = connMan.isBatchMode();

        try
        {
            if(log.isDebugEnabled())
            {
                log.debug(
                        "PB is in internal tx: "
                                + broker.isInTransaction()
                                + "  broker was: "
                                + broker);
            }
            // all neccessary db operations are executed within a PersistenceBroker transaction:
            if(!broker.isInTransaction())
            {
                log.error("PB associated with current odmg-tx is not in tx");
                throw new TransactionAbortedException("Underlying PB is not in tx, was begin call done before commit?");
            }

            // Committing has to be done in two phases. First implicitly upgrade to lock on all related
            // objects of objects in this transaction. Then the list of locked objects has to be
            // reordered to solve referential integrity dependencies, then the objects are
            // written into the database.

            // 0. turn on the batch mode
            connMan.setBatchMode(true);

            // 1. mark objects no longer available in collection
            // for delete and add new found objects
            checkAllEnvelopes(broker);

            // 2. mark all dependend objects for cascading insert/delete
            cascadingDependents();

            // 3. upgrade implicit locks.
            //upgradeImplicitLocksAndCheckIfCommitIsNeeded();
            upgradeLockIfNeeded();

            // 4. Reorder objects
            reorder();
//            System.out.println("## ordering: ");
//            for(int i = 0; i < mvOrderOfIds.size(); i++)
//            {
//                System.out.println("" + mvOrderOfIds.get(i));
//            }
//            System.out.println("## ordering end");

            // 5. write objects.
            writeAllEnvelopes(reuse);

            // 6. execute batch
            connMan.executeBatch();

            // 7. Update all Envelopes to new CleanState
            prepareForReuse(reuse);

            // 6. commit cleanup
            afterWriteCleanup();

        }
        catch(Exception e)
        {
            connMan.clearBatch();
            /*
            arminw:
            log only a warn message, because in top-level methods
            a error log will be done ditto
            */
            if(e instanceof OptimisticLockException)
            {
                // make error log to show the full stack trace one time
                log.error("Optimistic lock exception while write objects", e);
                // PB OptimisticLockException should be clearly signalled to the user
                Object sourceObject = ((OptimisticLockException) e).getSourceObject();
                throw new LockNotGrantedException("Optimistic lock exception occur, source object was (" + sourceObject + ")," +
                        " message was (" + e.getMessage() + ")");
            }
            else if(!(e instanceof RuntimeException))
            {
                log.warn("Error while write objects for tx " + transaction, e);
                throw new ODMGRuntimeException("Unexpected error while write objects: " + e.getMessage());
            }
            else
            {
                log.warn("Error while write objects for tx " + transaction, e);
                throw (RuntimeException) e;
            }
        }
        finally
        {
            needsCommit = false;
            connMan.setBatchMode(saveBatchMode);
        }
    }
78514
public boolean releaseLock(TransactionImpl tx, Object obj)
    {
        LockEntry writer = getWriter(obj);
        if (writer != null && writer.isOwnedBy(tx))
        {
            removeWriter(writer);
            return true;
        }
        if (hasReadLock(tx, obj))
        {
            removeReader(tx, obj);
            return true;
        }
        return false;
    }
406622
protected final void unLock(ObjectManagerState objectManagerState)
    {
        synchronized (objectManagerState.transactionUnlockSequenceLock) {
            unlockSequence = objectManagerState.getNewGlobalTransactionUnlockSequence();
            lockingTransaction = null;
        } // synchronized.
    }
404164
public final void commit(final PersistentTransaction transaction) throws SevereMessageStoreException
    {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(tc, "commit", "Transaction=" + transaction);

        if (STATE_END_PRECOMMIT == _state)
        {
            // normal processing
        }
        else
        {
            if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())  SibTr.exit(tc, "commit");
            throw new TaskListException(_state);
        }

        _state = STATE_BEGIN_COMMIT;

        Task task = _firstTask;
        while (null != task)
        {
            task.commitInternal(transaction);
            task = task._nextTask;
        }

        task = _firstTask;
        while (null != task)
        {
            task.commitExternal(transaction);
            task = task._nextTask;
        }

        _state = STATE_END_COMMIT;

        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())  SibTr.exit(tc, "commit");
    }