public void add(final OIdentifiable identifiable) { if (identifiable == null) throw new NullPointerException("Impossible to add a null identifiable in a ridbag"); if (identifiable.getIdentity().isValid()) { Change counter = changes.get(identifiable); if (counter == null) changes.put(identifiable, new DiffChange(1)); else { if (counter.isUndefined()) { counter = getAbsoluteValue(identifiable); changes.put(identifiable, counter); } counter.increment(); } } else { final OModifiableInteger counter = newEntries.get(identifiable); if (counter == null) newEntries.put(identifiable, new OModifiableInteger(1)); else counter.increment(); } if (size >= 0) size++; if (this.owner != null) ORecordInternal.track(this.owner, identifiable); if (updateOwner) fireCollectionChangedEvent( new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>( OMultiValueChangeEvent.OChangeType.ADD, identifiable, identifiable, null, false)); }
public void remove(OIdentifiable identifiable) { if (removeFromNewEntries(identifiable)) { if (size >= 0) size--; } else { final Change counter = changes.get(identifiable); if (counter == null) { // Not persistent keys can only be in changes or newEntries if (identifiable.getIdentity().isPersistent()) { changes.put(identifiable, new DiffChange(-1)); size = -1; } else // Return immediately to prevent firing of event return; } else { counter.decrement(); if (size >= 0) if (counter.isUndefined()) size = -1; else size--; } } if (this.owner != null) ORecordInternal.unTrack(this.owner, identifiable); if (updateOwner) fireCollectionChangedEvent( new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>( OMultiValueChangeEvent.OChangeType.REMOVE, identifiable, null, identifiable, false)); }
@Override public boolean convertRecords2Links() { final Map<OIdentifiable, Change> newChangedValues = new HashMap<OIdentifiable, Change>(); for (Map.Entry<OIdentifiable, Change> entry : changes.entrySet()) { OIdentifiable identifiable = entry.getKey(); if (identifiable instanceof ORecord) { ORID identity = identifiable.getIdentity(); ORecord record = (ORecord) identifiable; identity = record.getIdentity(); newChangedValues.put(identity, entry.getValue()); } else newChangedValues.put(entry.getKey().getIdentity(), entry.getValue()); } for (Map.Entry<OIdentifiable, Change> entry : newChangedValues.entrySet()) { if (entry.getKey() instanceof ORecord) { ORecord record = (ORecord) entry.getKey(); newChangedValues.put(record, entry.getValue()); } else return false; } newEntries.clear(); changes.clear(); changes.putAll(newChangedValues); return true; }
@Override public void setOwner(ORecord owner) { if (owner != null && this.owner != null && !this.owner.equals(owner)) { throw new IllegalStateException( "This data structure is owned by document " + owner + " if you want to use it in other document create new rid bag instance and copy content of current one."); } if (this.owner != null) { for (OIdentifiable entry : newEntries.keySet()) { ORecordInternal.unTrack(this.owner, entry); } for (OIdentifiable entry : changes.keySet()) { ORecordInternal.unTrack(this.owner, entry); } } this.owner = owner; if (this.owner != null) { for (OIdentifiable entry : newEntries.keySet()) { ORecordInternal.track(this.owner, entry); } for (OIdentifiable entry : changes.keySet()) { ORecordInternal.track(this.owner, entry); } } }
@Override public void convertLinks2Records() { TreeMap<OIdentifiable, Change> newChanges = new TreeMap<OIdentifiable, Change>(); for (Map.Entry<OIdentifiable, Change> entry : changes.entrySet()) { final OIdentifiable key = entry.getKey().getRecord(); if (key != null && this.owner != null) { ORecordInternal.unTrack(this.owner, entry.getKey()); ORecordInternal.track(this.owner, key); } newChanges.put((key == null) ? entry.getKey() : key, entry.getValue()); } changes.clear(); changes.putAll(newChanges); }
@Override public int deserialize(byte[] stream, int offset) { final long fileId = OLongSerializer.INSTANCE.deserializeLiteral(stream, offset); offset += OLongSerializer.LONG_SIZE; final long pageIndex = OLongSerializer.INSTANCE.deserializeLiteral(stream, offset); offset += OLongSerializer.LONG_SIZE; final int pageOffset = OIntegerSerializer.INSTANCE.deserializeLiteral(stream, offset); offset += OIntegerSerializer.INT_SIZE; // Cached bag size. Not used after 1.7.5 offset += OIntegerSerializer.INT_SIZE; if (fileId == -1) collectionPointer = null; else collectionPointer = new OBonsaiCollectionPointer(fileId, new OBonsaiBucketPointer(pageIndex, pageOffset)); this.size = -1; changes.putAll(ChangeSerializationHelper.INSTANCE.deserializeChanges(stream, offset)); return offset; }
private Map.Entry<OIdentifiable, Integer> nextChangedNotRemovedSBTreeEntry( Iterator<Map.Entry<OIdentifiable, Integer>> iterator) { while (iterator.hasNext()) { final Map.Entry<OIdentifiable, Integer> entry = iterator.next(); final Change change = changes.get(entry.getKey()); if (change == null) return entry; final int newValue = change.applyTo(entry.getValue()); if (newValue > 0) return new Map.Entry<OIdentifiable, Integer>() { @Override public OIdentifiable getKey() { return entry.getKey(); } @Override public Integer getValue() { return newValue; } @Override public Integer setValue(Integer value) { throw new UnsupportedOperationException(); } }; } return null; }
public void confirmDelete() { collectionPointer = null; changes.clear(); newEntries.clear(); size = 0; if (changeListeners != null) changeListeners.clear(); changeListeners = null; }
@Override public void remove() { if (currentRemoved) throw new IllegalStateException("Current element has already been removed"); if (currentValue == null) throw new IllegalStateException("Next method was not called for given iterator"); if (removeFromNewEntries(currentValue)) { if (size >= 0) size--; } else { Change counter = changedValues.get(currentValue); if (counter != null) { counter.decrement(); if (size >= 0) if (counter.isUndefined()) size = -1; else size--; } else { if (nextChange != null) { changedValues.put(currentValue, new DiffChange(-1)); changedValuesIterator = changedValues.tailMap(nextChange.getKey(), false).entrySet().iterator(); } else { changedValues.put(currentValue, new DiffChange(-1)); } size = -1; } } if (OSBTreeRidBag.this.owner != null) ORecordInternal.unTrack(OSBTreeRidBag.this.owner, currentValue); if (updateOwner) fireCollectionChangedEvent( new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>( OMultiValueChangeEvent.OChangeType.REMOVE, currentValue, null, currentValue, false)); currentRemoved = true; }
@Override public boolean contains(OIdentifiable identifiable) { if (newEntries.containsKey(identifiable)) return true; Change counter = changes.get(identifiable); if (counter != null) { AbsoluteChange absoluteValue = getAbsoluteValue(identifiable); if (counter.isUndefined()) { changes.put(identifiable, absoluteValue); } counter = absoluteValue; } else { counter = getAbsoluteValue(identifiable); } return counter.applyTo(0) > 0; }
@Override public void reset() { newEntryIterator = newEntries.entrySet().iterator(); this.changedValuesIterator = changedValues.entrySet().iterator(); if (sbTreeIterator != null) this.sbTreeIterator.reset(); nextChange = nextChangedNotRemovedEntry(changedValuesIterator); if (sbTreeIterator != null) nextSBTreeEntry = nextChangedNotRemovedSBTreeEntry(sbTreeIterator); }
private RIDBagIterator( IdentityHashMap<OIdentifiable, OModifiableInteger> newEntries, NavigableMap<OIdentifiable, Change> changedValues, SBTreeMapEntryIterator sbTreeIterator, boolean convertToRecord) { newEntryIterator = newEntries.entrySet().iterator(); this.changedValues = changedValues; this.convertToRecord = convertToRecord; this.changedValuesIterator = changedValues.entrySet().iterator(); this.sbTreeIterator = sbTreeIterator; nextChange = nextChangedNotRemovedEntry(changedValuesIterator); if (sbTreeIterator != null) nextSBTreeEntry = nextChangedNotRemovedSBTreeEntry(sbTreeIterator); }
private AbsoluteChange getAbsoluteValue(OIdentifiable identifiable) { final OSBTreeBonsai<OIdentifiable, Integer> tree = loadTree(); try { Integer oldValue; if (tree == null) oldValue = 0; else oldValue = tree.get(identifiable); if (oldValue == null) oldValue = 0; final Change change = changes.get(identifiable); return new AbsoluteChange(change == null ? oldValue : change.applyTo(oldValue)); } finally { releaseTree(); } }
/** * Recalculates real bag size. * * @return real size */ private int updateSize() { int size = 0; if (collectionPointer != null) { final OSBTreeBonsai<OIdentifiable, Integer> tree = loadTree(); try { size = tree.getRealBagSize(changes); } finally { releaseTree(); } } else { for (Change change : changes.values()) { size += change.applyTo(0); } } for (OModifiableInteger diff : newEntries.values()) { size += diff.getValue(); } this.size = size; return size; }
@Override public int serialize(byte[] stream, int offset, UUID ownerUuid) { for (Map.Entry<OIdentifiable, OModifiableInteger> entry : newEntries.entrySet()) { OIdentifiable identifiable = entry.getKey(); assert identifiable instanceof ORecord; Change c = changes.get(identifiable); final int delta = entry.getValue().intValue(); if (c == null) changes.put(identifiable, new DiffChange(delta)); else c.applyDiff(delta); } newEntries.clear(); final ORecordSerializationContext context; boolean remoteMode = ODatabaseRecordThreadLocal.INSTANCE.get().getStorage() instanceof OStorageProxy; if (remoteMode) { context = null; } else context = ORecordSerializationContext.getContext(); // make sure that we really save underlying record. if (collectionPointer == null) { if (context != null) { final int clusterId = getHighLevelDocClusterId(); assert clusterId > -1; collectionPointer = ODatabaseRecordThreadLocal.INSTANCE .get() .getSbTreeCollectionManager() .createSBTree(clusterId, ownerUuid); } } OBonsaiCollectionPointer collectionPointer; if (this.collectionPointer != null) collectionPointer = this.collectionPointer; else { collectionPointer = OBonsaiCollectionPointer.INVALID; } OLongSerializer.INSTANCE.serializeLiteral(collectionPointer.getFileId(), stream, offset); offset += OLongSerializer.LONG_SIZE; OBonsaiBucketPointer rootPointer = collectionPointer.getRootPointer(); OLongSerializer.INSTANCE.serializeLiteral(rootPointer.getPageIndex(), stream, offset); offset += OLongSerializer.LONG_SIZE; OIntegerSerializer.INSTANCE.serializeLiteral(rootPointer.getPageOffset(), stream, offset); offset += OIntegerSerializer.INT_SIZE; // Keep this section for binary compatibility with versions older then 1.7.5 OIntegerSerializer.INSTANCE.serializeLiteral(size, stream, offset); offset += OIntegerSerializer.INT_SIZE; if (context == null) { ChangeSerializationHelper.INSTANCE.serializeChanges( changes, OLinkSerializer.INSTANCE, stream, offset); } else { context.push(new ORidBagUpdateSerializationOperation(changes, collectionPointer)); // 0-length serialized list of changes OIntegerSerializer.INSTANCE.serializeLiteral(0, stream, offset); offset += OIntegerSerializer.INT_SIZE; } return offset; }
private int getChangesSerializedSize() { Set<OIdentifiable> changedIds = new HashSet<OIdentifiable>(changes.keySet()); changedIds.addAll(newEntries.keySet()); return ChangeSerializationHelper.INSTANCE.getChangesSerializedSize(changedIds.size()); }
public void clearChanges() { changes.clear(); }