synchronized List<Long> addUpdates(long txId, TxContext txContext, boolean isTrialRun) {
		if (isSingleSession) {
			//no need to record history
			return null;
		}
		
		ArrayList<TxObjInfo> updatesAndDeletes = txContext.getUpdatesAndDeletes();
		
		//first, check for conflicts
		ArrayList<Long> conflicts = null;
		for (TxObjInfo clientInfo: updatesAndDeletes) {
			long oid = clientInfo.getOid();
			long ots = clientInfo.getTS();
			//At this point we should not ignore objects that are apparently new!
			//Why? Even if the object appears new, the OID may be in use, which 
			//may present a conflict.

			TxObjInfo serverInfo = updateSummary.get(oid);
			//OLD:
			//Did the current transaction begin before the other was committed?
			//I.e. is the updateTimeStamp higher than the readTimeStamp of the current TX?
			//NEW: We just check whether the cached TS equals the expected TS. 
			//If not, we have a conflict. Note, that the new timestamp may be LOWER than the
			//cached timestamp if the object was updated AFTER the current TX started, but
			//before the current TX first accessed the object.
			//System.out.println("TxM-au: " + oid + " ots=" + ots + "   txTS=" + (serverInfo != null?serverInfo.getTS():"null"));
			if (serverInfo != null && serverInfo.getTxId() != ots) {
				if (clientInfo.isDeleted() && serverInfo.isDeleted()) {
					//okay, ignore
					//continue;
					//TODO For now we don't ignore these. To ignore these, we have to report back
					//so that there will be no attempts on updating any indexes. Furthermore,
					//it is not obvious that this is the right thing to do, because the TX may 
					//semantically rely on having deleted an object, however the object is already 
					//gone (for example if the number of deleted objects counts).
				}
				if (conflicts == null) {
					conflicts = new ArrayList<>();
				}
				conflicts.add(oid);
			}
		}
		if (conflicts != null || isTrialRun) {
			return conflicts;
		}
		
		//apply updates
		updateHistory.put(txId, updatesAndDeletes);
		for (TxObjInfo info: updatesAndDeletes) {
			// +1 to ensure conflicts even with latest transaction
			info.setTxId(txId);
			updateSummary.put(info.getOid(), info);
		}
		//not very clean: 'null' indicates no conflicts.
		return null;
	}
synchronized List < Long > addUpdates ( long txId , TxContext txContext , boolean isTrialRun ) { if ( isSingleSession ) { return null ; } ArrayList < TxObjInfo > updatesAndDeletes = txContext . getUpdatesAndDeletes ( ) ; ArrayList < Long > conflicts = null ; for ( TxObjInfo clientInfo : updatesAndDeletes ) { long oid = clientInfo . getOid ( ) ; long ots = clientInfo . getTS ( ) ; TxObjInfo serverInfo = updateSummary . get ( oid ) ; if ( serverInfo != null && serverInfo . getTxId ( ) != ots ) { if ( clientInfo . isDeleted ( ) && serverInfo . isDeleted ( ) ) { } if ( conflicts == null ) { conflicts = new ArrayList < > ( ) ; } conflicts . add ( oid ) ; } } if ( conflicts != null || isTrialRun ) { return conflicts ; } updateHistory . put ( txId , updatesAndDeletes ) ; for ( TxObjInfo info : updatesAndDeletes ) { info . setTxId ( txId ) ; updateSummary . put ( info . getOid ( ) , info ) ; } return null ; }
Add updates of a transaction to the history tree.
To be called when starting a new commit().
@param txId
@param txContext
@return A list of conflicting objects or {@code null} if there are no conflicts