/**
* 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;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
import com.persistit.Exchange.Sequence;
import com.persistit.Management.RecordInfo;
import com.persistit.ValueHelper.RawValueWriter;
import com.persistit.exception.PersistitException;
import com.persistit.exception.RebalanceException;
import com.persistit.policy.JoinPolicy;
import com.persistit.policy.SplitPolicy;
public class BufferTest extends PersistitUnitTestCase {
int leftn;
int rightn;
int leftklen;
int rightklen;
int leftvlen;
int rightvlen;
int leftShorten;
int rightShorten;
@Test
public void testSimpleSplitAndJoin() throws Exception {
final Exchange ex = _persistit.getExchange("persistit", "BufferTest", true);
final StringBuilder sb = new StringBuilder();
final Buffer b1 = ex.getBufferPool().get(ex.getVolume(), 1, true, false);
final Buffer b2 = ex.getBufferPool().get(ex.getVolume(), 2, true, false);
final RawValueWriter vwriter = new RawValueWriter();
b1.init(Buffer.PAGE_TYPE_DATA);
b2.init(Buffer.PAGE_TYPE_DATA);
b1.getFastIndex();
b2.getFastIndex();
final Key key = new Key((Persistit) null);
final Key indexKey = new Key((Persistit) null);
final Value value = new Value((Persistit) null);
for (int i = 'a'; i < 'z'; i++) {
sb.append((char) i).append((char) i);
key.to(sb);
value.putString(sb);
vwriter.init(value);
b1.putValue(key, vwriter);
}
sb.setLength(20);
key.to(sb);
final int foundAt = b1.findKey(key);
b1.split(b2, key, vwriter, foundAt, indexKey, Sequence.NONE, SplitPolicy.NICE_BIAS);
final RecordInfo info = b2.getRecords()[0];
info.getKeyState().copyTo(key);
final Key key1 = new Key(key);
final Key key2 = new Key(key);
key1.nudgeLeft();
key2.nudgeRight();
final int foundAt1 = b1.findKey(key1);
final int foundAt2 = b2.findKey(key2);
b1.join(b2, foundAt1, foundAt2, key1, key2, JoinPolicy.EVEN_BIAS);
final RecordInfo r = b1.getRecords()[b1.getRecords().length - 1];
r.getKeyState().copyTo(key);
assertTrue(key.toString().contains("ttuuvv"));
b1.release();
b2.release();
}
@Test
public void testProblematicJoins() throws Exception {
final Exchange ex = _persistit.getExchange("persistit", "BufferTest", true);
final Buffer b1 = ex.getBufferPool().get(ex.getVolume(), 1, true, false);
final Buffer b2 = ex.getBufferPool().get(ex.getVolume(), 2, true, false);
leftn = 200;
rightn = 200;
leftklen = 20;
rightklen = 20;
leftvlen = 20;
rightvlen = 20;
leftShorten = 0;
rightShorten = 0;
combo(ex, b1, b2);
leftn = 1000;
rightn = 1000;
combo(ex, b1, b2);
leftShorten = 2;
rightShorten = 7;
combo(ex, b1, b2);
}
/*
* Note: runs for about 3 minutes -- ignored for now
*/
@Ignore
@Test
public void manyJoins() throws Exception {
final Exchange ex = _persistit.getExchange("persistit", "BufferTest", true);
final Buffer b1 = ex.getBufferPool().get(ex.getVolume(), 1, true, false);
final Buffer b2 = ex.getBufferPool().get(ex.getVolume(), 2, true, false);
for (leftn = 200; leftn < 800; leftn += 200) {
for (rightn = 200; rightn < 800; rightn += 200) {
for (leftklen = 5; leftklen < 40; leftklen += 10) {
for (rightklen = 5; rightklen < 40; rightklen += 10) {
for (leftvlen = 10; leftvlen <= 100; leftvlen += 10) {
for (rightvlen = 10; rightvlen <= 100; rightvlen += 30) {
for (leftShorten = 0; leftShorten < 10; leftShorten += 3) {
for (rightShorten = 0; rightShorten < 10; rightShorten += 3) {
combo(ex, b1, b2);
}
}
}
}
}
}
}
}
}
private boolean combo(final Exchange ex, final Buffer b1, final Buffer b2) throws Exception {
try {
b1.init(Buffer.PAGE_TYPE_DATA);
b1.clearSlack();
b2.init(Buffer.PAGE_TYPE_DATA);
b2.clearSlack();
final int n1 = fillPage(ex, b1, 1, leftn, leftklen, leftvlen);
fillPage(ex, b2, n1, 1, leftklen, leftvlen);
final int n2 = fillPage(ex, b2, n1 + 1, rightn, rightklen, rightvlen);
if (leftShorten > 0) {
fillPage(ex, b1, 1, n1 - 1, leftklen, leftvlen - leftShorten);
}
if (rightShorten > 0) {
fillPage(ex, b2, n1 + 1, n2 - n1 - 1, rightklen, rightvlen - rightShorten);
}
b1.verify(null, null);
b2.verify(null, null);
joinPages(ex, b1, b2, n1, n1);
b1.verify(null, null);
b2.verify(null, null);
return false;
} catch (final RebalanceException e) {
return true;
}
}
private int fillPage(final Exchange ex, final Buffer b, final int k, final int n, final int klen, final int vlen)
throws PersistitException {
final RawValueWriter vwriter = new RawValueWriter();
vwriter.init(ex.getValue());
final StringBuilder sb = new StringBuilder(vlen);
while (sb.length() < vlen) {
sb.append(RED_FOX);
}
sb.setLength(vlen);
ex.getValue().put(sb.toString());
int i = -1;
int offset = 0;
for (i = k; i < k + n; i++) {
ex.getKey().clear().append(String.format("%05d%" + klen + "s", i, ""));
offset = b.putValue(ex.getKey(), vwriter);
if (offset == -1) {
break;
}
}
for (int j = i; j >= i - 1; j--) {
ex.getValue().clear();
ex.getKey().clear().append(String.format("%05d%" + klen + "s", j, ""));
offset = b.putValue(ex.getKey(), vwriter);
if (offset != -1) {
return j;
}
}
return -1;
}
private void joinPages(final Exchange ex, final Buffer b1, final Buffer b2, final int key1, final int key2)
throws PersistitException {
ex.getKey().clear().append(String.format(String.format("%05d%" + leftklen + "s", key1, "")));
final int foundAt1 = b1.findKey(ex.getKey());
ex.getKey().clear().append(String.format(String.format("%05d%" + leftklen + "s", key2, "")));
int foundAt2 = b2.findKey(ex.getKey());
if ((foundAt2 & Buffer.EXACT_MASK) != 0) {
foundAt2 += 3;
}
b1.join(b2, foundAt1, foundAt2, ex.getAuxiliaryKey1(), ex.getAuxiliaryKey2(), JoinPolicy.EVEN_BIAS);
}
/*
* ----------
*/
String keyString(final char fill, final int length, final int prefix, final int width, final int k) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < prefix && i < length; i++) {
sb.append(fill);
}
sb.append(String.format("%0" + width + "d", k));
for (int i = length - sb.length(); i < length; i++) {
sb.append(fill);
}
sb.setLength(length);
return sb.toString();
}
}