package com.jivesoftware.os.amza.service.storage.delta; import com.jivesoftware.os.amza.api.stream.RowType; import com.jivesoftware.os.amza.api.wal.KeyUtil; import com.jivesoftware.os.amza.api.wal.WALPointer; import com.jivesoftware.os.amza.api.wal.WALValue; import java.util.AbstractMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; /** * TODO replace with stream! * * @author jonathan.colt */ class DeltaPeekableElmoIterator implements Iterator<Map.Entry<byte[], WALValue>> { private final Iterator<Map.Entry<byte[], WALPointer>> iterator; private final Iterator<Map.Entry<byte[], WALPointer>> compactingIterator; private final WALRowHydrator hydrator; private final WALRowHydrator compactingHydrator; private final boolean hydrateValues; private Map.Entry<byte[], WALValue> last; private Map.Entry<byte[], WALPointer> iNext; private Map.Entry<byte[], WALPointer> cNext; public DeltaPeekableElmoIterator(Iterator<Map.Entry<byte[], WALPointer>> iterator, Iterator<Map.Entry<byte[], WALPointer>> compactingIterator, WALRowHydrator hydrator, WALRowHydrator compactingHydrator, boolean hydrateValues) { this.iterator = new OverConsumingEntryIterator<>(iterator); this.compactingIterator = new OverConsumingEntryIterator<>(compactingIterator); this.hydrator = hydrator; this.compactingHydrator = compactingHydrator; this.hydrateValues = hydrateValues; } public void eos() { last = null; } public Map.Entry<byte[], WALValue> last() { return last; } @Override public boolean hasNext() { return (iNext != null || cNext != null) || iterator.hasNext() || compactingIterator.hasNext(); } @Override public Map.Entry<byte[], WALValue> next() { if (iNext == null && iterator.hasNext()) { iNext = iterator.next(); } if (cNext == null && compactingIterator.hasNext()) { cNext = compactingIterator.next(); } if (iNext != null && cNext != null) { int compare = KeyUtil.compare(iNext.getKey(), cNext.getKey()); if (compare == 0) { if (iNext.getValue().getTimestampId() > cNext.getValue().getTimestampId()) { last = hydrate(iNext, hydrator); } else { last = hydrate(cNext, compactingHydrator); } iNext = null; cNext = null; } else if (compare < 0) { last = hydrate(iNext, hydrator); iNext = null; } else { last = hydrate(cNext, compactingHydrator); cNext = null; } } else if (iNext != null) { last = hydrate(iNext, hydrator); iNext = null; } else if (cNext != null) { last = hydrate(cNext, compactingHydrator); cNext = null; } else { throw new NoSuchElementException(); } return last; } // TODO fix this Ugly Abomination private Map.Entry<byte[], WALValue> hydrate(Map.Entry<byte[], WALPointer> entry, WALRowHydrator valueHydrator) { try { WALPointer pointer = entry.getValue(); WALValue hydrated = null; if (hydrateValues) { if (pointer.getHasValue()) { hydrated = new WALValue(RowType.primary, pointer.getValue(), pointer.getTimestampId(), pointer.getTombstoned(), pointer.getVersion()); } else { hydrated = valueHydrator.hydrate(entry.getValue().getFp()); } } else { hydrated = new WALValue(RowType.primary, null, pointer.getTimestampId(), pointer.getTombstoned(), pointer.getVersion()); } return new AbstractMap.SimpleEntry<>(entry.getKey(), hydrated); } catch (Exception e) { throw new RuntimeException("Failed to hydrate while iterating delta", e); } } @Override public void remove() { throw new UnsupportedOperationException("Not supported ever!"); } public void close() { if (compactingHydrator != null) { compactingHydrator.closeHydrator(); } } }