/** Checks if the given detail conflicts with this detail. */ boolean conflictsWith(AccessedObjectsDetailImpl other) { if (other == null) { return false; } // A conflict occurs if two details have write sets that // intersect, or if the write set of either set intersects // with the other's read set. We therefore iterate over // each detail's write set and check if the second detail // had a source that accessed an object with the same key // as the write access from the first detail. for (AccessedObject o : writes) { Map<Object, Object> objIdToDescription = other.sourceToObjIdAndDescription.get(o.getSource()); if (objIdToDescription != null && objIdToDescription.containsKey(o.getObjectId())) { return true; } } for (AccessedObject o : other.writes) { Map<Object, Object> objIdToDescription = sourceToObjIdAndDescription.get(o.getSource()); if (objIdToDescription != null && objIdToDescription.containsKey(o.getObjectId())) { return true; } } return false; }
/** Adds an {@code AccessedObject} to the list of accessed objects. */ void addAccess(AccessedObject accessedObject) { boolean added = accessList.add(accessedObject); // if this is the first time the object has been accessed, // we may need to add its id to the set of descriptions, // and if it was a write, add it to the list. if (added) { String source = accessedObject.getSource(); Map<Object, Object> idToDescription = sourceToObjIdAndDescription.get(source); if (idToDescription == null) { idToDescription = new HashMap<Object, Object>(); sourceToObjIdAndDescription.put(source, idToDescription); } // if we didn't already have a description set for // this object, put its Id in the map so we have a // recorded access of it. We use the keyset of this // map when checking for conflicts, so every access // needs to be recorded in it Object objId = accessedObject.getObjectId(); if (!idToDescription.containsKey(objId)) { idToDescription.put(objId, null); } // keep track of the write accesses in case we later // need to determine whether this detail conflicted // with another. if (accessedObject.getAccessType().equals(AccessType.WRITE)) { writes.add(accessedObject); } } }
/** * Returns a formatted list of accesses with one access per line. * * @param accessedObjects a {@code List} of {@code AccessedObject} * @return a formatted representation of the accessed objects */ private String formatAccesses(List<AccessedObject> accessedObjects) { StringBuilder formatted = new StringBuilder(); int count = 0; for (AccessedObject object : accessedObjects) { if (++count > accessesToShow) break; try { formatted.append( String.format( "[source: %s] %-5s %s, " + "description: %s%n", object.getSource(), object.getAccessType(), object.getObjectId(), object.getDescription())); } catch (Throwable t) { // calling toString() on the object id or the description // may have failed, though in practice (in the current // implementation) only the description will have caused // any trouble, so we can include some detail about // both the access and the failure formatted.append( String.format( "[source: %s] %-5s %s [%s." + "toString() threw: %s]%n", object.getSource(), object.getAccessType(), object.getObjectId(), object.getDescription().getClass(), t)); } } // if we went over the max count then it means there was still // more to show, so add a message about the truncation if (--count == accessesToShow) formatted.append( String.format( "[%d further accesses truncated]%n", accessedObjects.size() - accessesToShow)); return formatted.toString(); }