/**
* Copyright 2011-2012 Akiban Technologies, 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 com.persistit.unit;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import com.persistit.Exchange;
import com.persistit.Exchange.TraverseVisitor;
import com.persistit.Key;
import com.persistit.PersistitUnitTestCase;
import com.persistit.ReadOnlyExchange;
import com.persistit.exception.PersistitException;
public class TraverseVisitorTest extends PersistitUnitTestCase {
private final AtomicInteger visited = new AtomicInteger();
private final AtomicInteger visitLimit = new AtomicInteger(Integer.MAX_VALUE);
private final AtomicBoolean reverse = new AtomicBoolean();
@Test
public void simpleTraverseVisitor() throws PersistitException {
final TraverseVisitor tv = new Exchange.TraverseVisitor() {
@Override
public boolean visit(final ReadOnlyExchange ex) {
visited.incrementAndGet();
return visited.get() < visitLimit.get();
}
};
doCombo(tv);
}
@Test
public void traverseVisitorNonMutatingTraverseMethods() throws Exception {
final TraverseVisitor tv = new Exchange.TraverseVisitor() {
@Override
public boolean visit(final ReadOnlyExchange ex) throws PersistitException {
visited.incrementAndGet();
final int v = visited.get();
return v < visitLimit.get();
}
};
doCombo(tv);
}
/**
* Demonstrates that a TraverseVisitor can (carefully) modify the Key of a
* supplied ReadOnlyExchange.
*
* @throws Exception
*/
@Test
public void testMutateKey() throws Exception {
final TraverseVisitor tv = new Exchange.TraverseVisitor() {
@Override
public boolean visit(final ReadOnlyExchange ex) throws PersistitException {
visited.incrementAndGet();
final int v = visited.get();
if (reverse.get()) {
final int k = ex.getKey().reset().decodeInt();
ex.getKey().clear().append(k - 1).append(0);
} else {
ex.getKey().append("a");
}
return v < visitLimit.get();
}
};
doCombo(tv);
}
private void doCombo(final TraverseVisitor tv) throws PersistitException {
final Exchange ex = _persistit.getExchange("persistit", "gogo", true);
final String mockValue = createString(64);
for (int i = 0; i < 1000; i++) {
ex.clear().append(i);
ex.getValue().put(mockValue);
ex.store();
}
final int max = Integer.MAX_VALUE;
doTraverse(ex, tv, false, Key.GT, max, 1000);
doTraverse(ex, tv, false, Key.GT, max, 1000);
doTraverse(ex, tv, false, Key.LT, max, 1000);
doTraverse(ex, tv, false, Key.LT, max, 1000);
doTraverse(ex, tv, false, Key.GT, 1, 1);
doTraverse(ex, tv, false, Key.GT, 1, 1);
doTraverse(ex, tv, false, Key.GT, 10, 10);
doTraverse(ex, tv, false, Key.GT, 10, 10);
doTraverse(ex, tv, false, Key.LT, 1, 1);
doTraverse(ex, tv, false, Key.LT, 1, 1);
doTraverse(ex, tv, false, Key.LT, 10, 10);
doTraverse(ex, tv, false, Key.LT, 10, 10);
doTraverse(ex, tv, true, Key.GT, max, 1000);
doTraverse(ex, tv, true, Key.GT, max, 1000);
doTraverse(ex, tv, true, Key.LT, max, 1000);
doTraverse(ex, tv, true, Key.LT, max, 1000);
doTraverse(ex, tv, true, Key.GT, 1, 1);
doTraverse(ex, tv, true, Key.GT, 1, 1);
doTraverse(ex, tv, true, Key.GT, 10, 10);
doTraverse(ex, tv, true, Key.GT, 10, 10);
doTraverse(ex, tv, true, Key.LT, 1, 1);
doTraverse(ex, tv, true, Key.LT, 1, 1);
doTraverse(ex, tv, true, Key.LT, 10, 10);
doTraverse(ex, tv, true, Key.LT, 10, 10);
doTraverse(ex, tv, false, Key.GTEQ, max, 1000);
doTraverse(ex, tv, false, Key.GTEQ, max, 1000);
doTraverse(ex, tv, false, Key.LTEQ, max, 1000);
doTraverse(ex, tv, false, Key.LTEQ, max, 1000);
doTraverseFrom(1, ex, tv, false, Key.GT, max, 998);
doTraverseFrom(1, ex, tv, false, Key.GTEQ, max, 999);
doTraverseFrom(998, ex, tv, false, Key.LT, max, 998);
doTraverseFrom(998, ex, tv, false, Key.LTEQ, max, 999);
doTraverseFrom(500, ex, tv, false, Key.EQ, max, 1);
doTraverseFrom(1001, ex, tv, false, Key.EQ, max, 0);
}
private void doTraverse(final Exchange ex, final TraverseVisitor tv, final boolean deep,
final Key.Direction direction, final int limit, final int expected) throws PersistitException {
ex.clear().append(direction == Key.LT || direction == Key.LTEQ ? Key.AFTER : Key.BEFORE);
doTraverse0(ex, tv, deep, direction, limit, expected);
}
private void doTraverseFrom(final int from, final Exchange ex, final TraverseVisitor tv, final boolean deep,
final Key.Direction direction, final int limit, final int expected) throws PersistitException {
ex.clear().append(from);
doTraverse0(ex, tv, deep, direction, limit, expected);
}
private void doTraverse0(final Exchange ex, final TraverseVisitor tv, final boolean deep,
final Key.Direction direction, final int limit, final int expected) throws PersistitException {
reverse.set(direction == Key.LT || direction == Key.LTEQ);
visited.set(0);
visitLimit.set(limit);
assertEquals(limit < 1000, ex.traverse(direction, deep, Integer.MAX_VALUE, tv));
assertEquals(expected, visited.get());
}
}