package com.jivesoftware.os.amza.service.storage.delta;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jivesoftware.os.amza.api.IoStats;
import com.jivesoftware.os.amza.api.filer.UIO;
import com.jivesoftware.os.amza.api.stream.FpKeyValueStream;
import com.jivesoftware.os.amza.api.stream.Fps;
import com.jivesoftware.os.amza.api.stream.RowType;
import com.jivesoftware.os.amza.api.wal.KeyUtil;
import com.jivesoftware.os.amza.api.wal.WALKey;
import com.jivesoftware.os.amza.api.wal.WALPointer;
import com.jivesoftware.os.amza.api.wal.WALRow;
import com.jivesoftware.os.amza.api.wal.WALValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListMap;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @author jonathan.colt
*/
public class DeltaPeekableElmoIteratorNGTest {
@Test
public void testSimple() throws Exception {
for (int r = 0; r < 10; r++) {
ConcurrentSkipListMap<byte[], WALPointer> wal = new ConcurrentSkipListMap<>(KeyUtil::compare);
ConcurrentSkipListMap<byte[], WALPointer> other = new ConcurrentSkipListMap<>(KeyUtil::compare);
Random rand = new Random();
NavigableSet<Byte> expected = new TreeSet<>();
NavigableSet<Byte> expectedBoth = new TreeSet<>();
final Map<Long, WALRow> fpRows = Maps.newHashMap();
for (int i = 0; i < 128; i++) {
if (rand.nextBoolean()) {
long timestamp = rand.nextInt(128);
byte[] prefix = new byte[]{(byte) i};
byte[] key = new byte[]{(byte) i};
WALPointer pointer = new WALPointer((long) i, timestamp, false, timestamp, false, null);
WALValue value = new WALValue(RowType.primary, UIO.longBytes((long) i), timestamp, false, timestamp);
wal.put(WALKey.compose(prefix, key), pointer);
fpRows.put((long) i, new WALRow(RowType.primary, prefix, key, value.getValue(), value.getTimestampId(), value.getTombstoned(), value
.getVersion()));
expected.add((byte) i);
expectedBoth.add((byte) i);
}
if (rand.nextBoolean()) {
long timestamp = rand.nextInt(128);
byte[] prefix = new byte[]{(byte) i};
byte[] key = new byte[]{(byte) i};
WALPointer pointer = new WALPointer((long) i, timestamp, false, timestamp, false, null);
WALValue value = new WALValue(RowType.primary, UIO.longBytes((long) i), timestamp, false, timestamp);
other.put(WALKey.compose(prefix, key), pointer);
fpRows.put((long) i, new WALRow(RowType.primary, prefix, key, value.getValue(), value.getTimestampId(), value.getTombstoned(), value
.getVersion()));
expectedBoth.add((byte) i);
}
}
WALRowHydrator hydrator = new WALRowHydrator() {
@Override
public boolean hydrate(IoStats ioStats, Fps fps, FpKeyValueStream fpKeyValueStream) throws Exception {
return fps.consume(fp -> {
WALRow row = fpRows.get(fp);
return fpKeyValueStream.stream(fp, row.rowType, row.prefix, row.key, row.value, row.timestamp, row.tombstoned, row.version);
});
}
@Override
public WALValue hydrate(long fp) throws Exception {
WALRow row = fpRows.get(fp);
return new WALValue(row.rowType, row.value, row.timestamp, row.tombstoned, row.version);
}
@Override
public void closeHydrator() {
}
};
DeltaPeekableElmoIterator deltaPeekableElmoIterator = new DeltaPeekableElmoIterator(
wal.entrySet().iterator(),
Iterators.<Map.Entry<byte[], WALPointer>>emptyIterator(),
hydrator,
hydrator,
true);
List<Byte> had = new ArrayList<>();
long[] lastV = {-1};
while (deltaPeekableElmoIterator.hasNext()) {
byte[] pk = deltaPeekableElmoIterator.next().getKey();
WALKey.decompose(txFpRawKeyValueEntryStream -> txFpRawKeyValueEntryStream.stream(-1, -1, null, pk, false, null, -1, false, -1, null),
(txId, fp, rowType, prefix, key, hasValue, value, valueTimestamp, valueTombstoned, valueVersion, entry) -> {
byte v = key[0];
had.add(v);
Assert.assertTrue(lastV[0] < v);
lastV[0] = v;
return true;
});
}
Assert.assertEquals(had, Lists.newArrayList(expected));
deltaPeekableElmoIterator = new DeltaPeekableElmoIterator(
wal.entrySet().iterator(),
other.entrySet().iterator(),
hydrator,
hydrator,
true);
had.clear();
lastV[0] = -1;
while (deltaPeekableElmoIterator.hasNext()) {
byte[] pk = deltaPeekableElmoIterator.next().getKey();
WALKey.decompose(txFpRawKeyValueEntryStream -> txFpRawKeyValueEntryStream.stream(-1, -1, null, pk, false, null, -1, false, -1, null),
(txId, fp, rowType, prefix, key, hasValue, value, valueTimestamp, valueTombstoned, valueVersion, entry) -> {
byte v = key[0];
had.add(v);
Assert.assertTrue(lastV[0] < v);
lastV[0] = v;
return true;
});
}
Assert.assertEquals(had, Lists.newArrayList(expectedBoth));
}
}
}