/*
* Copyright 2008-2009 LinkedIn, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.sdnplatform.sync.internal.store;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.junit.Test;
import org.sdnplatform.sync.IClosableIterator;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.error.SyncException;
import org.sdnplatform.sync.internal.TUtils;
import org.sdnplatform.sync.internal.store.IStorageEngine;
import org.sdnplatform.sync.internal.store.IStore;
import org.sdnplatform.sync.internal.util.ByteArray;
import static org.junit.Assert.*;
public abstract class AbstractStorageEngineT extends AbstractByteArrayStoreT {
@Override
public IStore<ByteArray, byte[]> getStore() {
return getStorageEngine();
}
public abstract IStorageEngine<ByteArray, byte[]> getStorageEngine();
public void testGetNoEntries() {
IClosableIterator<Entry<ByteArray, List<Versioned<byte[]>>>> it = null;
try {
IStorageEngine<ByteArray, byte[]> engine = getStorageEngine();
it = engine.entries();
while(it.hasNext())
fail("There shouldn't be any entries in this store.");
} finally {
if(it != null)
it.close();
}
}
@Test
public void testGetNoKeys() {
IClosableIterator<ByteArray> it = null;
try {
IStorageEngine<ByteArray, byte[]> engine = getStorageEngine();
it = engine.keys();
while(it.hasNext())
fail("There shouldn't be any entries in this store.");
} finally {
if(it != null)
it.close();
}
}
@Test
public void testPruneOnWrite() throws SyncException {
IStorageEngine<ByteArray, byte[]> engine = getStorageEngine();
Versioned<byte[]> v1 = new Versioned<byte[]>(new byte[] { 1 }, TUtils.getClock(1));
Versioned<byte[]> v2 = new Versioned<byte[]>(new byte[] { 2 }, TUtils.getClock(2));
Versioned<byte[]> v3 = new Versioned<byte[]>(new byte[] { 3 }, TUtils.getClock(1, 2));
ByteArray key = new ByteArray((byte) 3);
engine.put(key, v1);
engine.put(key, v2);
assertEquals(2, engine.get(key).size());
engine.put(key, v3);
assertEquals(1, engine.get(key).size());
}
@Test
public void testTruncate() throws Exception {
IStorageEngine<ByteArray, byte[]> engine = getStorageEngine();
Versioned<byte[]> v1 = new Versioned<byte[]>(new byte[] { 1 });
Versioned<byte[]> v2 = new Versioned<byte[]>(new byte[] { 2 });
Versioned<byte[]> v3 = new Versioned<byte[]>(new byte[] { 3 });
ByteArray key1 = new ByteArray((byte) 3);
ByteArray key2 = new ByteArray((byte) 4);
ByteArray key3 = new ByteArray((byte) 5);
engine.put(key1, v1);
engine.put(key2, v2);
engine.put(key3, v3);
engine.truncate();
IClosableIterator<Entry<ByteArray, List<Versioned<byte[]>>>> it = null;
try {
it = engine.entries();
while(it.hasNext()) {
fail("There shouldn't be any entries in this store.");
}
} finally {
if(it != null) {
it.close();
}
}
}
@Test
public void testCleanupTask() throws Exception {
IStorageEngine<ByteArray, byte[]> engine = getStorageEngine();
engine.setTombstoneInterval(500);
Versioned<byte[]> v1_1 = new Versioned<byte[]>(new byte[] { 1 }, TUtils.getClock(1));
Versioned<byte[]> v1_2 = new Versioned<byte[]>(null, TUtils.getClock(1, 1));
// add, update, delete
Versioned<byte[]> v2_1 = new Versioned<byte[]>(new byte[] { 1 }, TUtils.getClock(1));
Versioned<byte[]> v2_2 = new Versioned<byte[]>(new byte[] { 2 }, TUtils.getClock(1, 2));
Versioned<byte[]> v2_3 = new Versioned<byte[]>(null, TUtils.getClock(1, 2, 1));
// delete then add again
Versioned<byte[]> v3_1 = new Versioned<byte[]>(new byte[] { 1 }, TUtils.getClock(1));
Versioned<byte[]> v3_2 = new Versioned<byte[]>(null, TUtils.getClock(1, 2));
Versioned<byte[]> v3_3 = new Versioned<byte[]>(new byte[] { 2 }, TUtils.getClock(1, 2, 1));
// delete concurrent to update
Versioned<byte[]> v4_1 = new Versioned<byte[]>(new byte[] { 1 }, TUtils.getClock(1));
Versioned<byte[]> v4_2 = new Versioned<byte[]>(new byte[] { 2 }, TUtils.getClock(1, 2));
Versioned<byte[]> v4_3 = new Versioned<byte[]>(null, TUtils.getClock(1, 1));
ByteArray key1 = new ByteArray((byte) 3);
ByteArray key2 = new ByteArray((byte) 4);
ByteArray key3 = new ByteArray((byte) 5);
ByteArray key4 = new ByteArray((byte) 6);
engine.put(key1, v1_1);
assertEquals(1, engine.get(key1).size());
engine.put(key1, v1_2);
List<Versioned<byte[]>> r = engine.get(key1);
assertEquals(1, r.size());
assertNull(r.get(0).getValue());
engine.put(key2, v2_1);
engine.put(key2, v2_2);
engine.put(key2, v2_3);
engine.put(key3, v3_1);
engine.put(key3, v3_2);
engine.put(key4, v4_1);
engine.put(key4, v4_2);
engine.put(key4, v4_3);
engine.cleanupTask();
r = engine.get(key1);
assertEquals(1, r.size());
assertNull(r.get(0).getValue());
engine.put(key3, v3_3);
Thread.sleep(501);
engine.cleanupTask();
r = engine.get(key1);
assertEquals(0, r.size());
r = engine.get(key2);
assertEquals(0, r.size());
r = engine.get(key3);
assertEquals(1, r.size());
r = engine.get(key4);
assertEquals(2, r.size());
}
@SuppressWarnings("unused")
private boolean remove(List<byte[]> list, byte[] item) {
Iterator<byte[]> it = list.iterator();
boolean removedSomething = false;
while(it.hasNext()) {
if(TUtils.bytesEqual(item, it.next())) {
it.remove();
removedSomething = true;
}
}
return removedSomething;
}
}