/**
* 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 static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Properties;
import org.junit.Test;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.Management;
import com.persistit.PersistitUnitTestCase;
import com.persistit.Value;
import com.persistit.Volume;
import com.persistit.exception.PersistitException;
import com.persistit.exception.VolumeFullException;
public class TemporaryVolumeTest1 extends PersistitUnitTestCase {
private Volume _volume;
@Override
public void setUp() throws Exception {
super.setUp();
_volume = _persistit.createTemporaryVolume();
}
@Override
public void tearDown() throws Exception {
_volume.close();
_volume = null;
super.tearDown();
}
@Test
public void test1() throws PersistitException {
store1();
fetch1a();
fetch1b();
fetch1c();
}
private void store1() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1", true);
final StringBuilder sb = new StringBuilder();
for (int i = 1; i < 400; i++) {
sb.setLength(0);
sb.append((char) (i / 20 + 64));
sb.append((char) (i % 20 + 64));
exchange.clear().append(sb);
exchange.getValue().put("Record #" + i);
exchange.store();
}
}
private void fetch1a() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1", false);
final StringBuilder sb = new StringBuilder();
for (int i = 1; i < 400; i++) {
sb.setLength(0);
sb.append((char) (i / 20 + 64));
sb.append((char) (i % 20 + 64));
exchange.clear().append(sb);
exchange.fetch();
assertTrue(exchange.getValue().isDefined());
assertEquals("Record #" + i, exchange.getValue().getString());
}
}
private void fetch1b() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1", false);
final StringBuilder sb = new StringBuilder();
for (int i = 1; i < 400; i++) {
sb.setLength(0);
sb.append((char) (i % 20 + 64));
sb.append((char) (i / 20 + 64));
exchange.clear().append(sb);
exchange.fetch();
final int k = (i / 20) + (i % 20) * 20;
assertEquals(exchange.getValue().getString(), "Record #" + k);
}
}
private void fetch1c() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1", false);
int count;
exchange.getKey().clear().append(Key.BEFORE);
final StringBuilder sb = new StringBuilder();
for (count = 1; exchange.next() && count < 10000; count++) {
sb.setLength(0);
sb.append((char) (count / 20 + 64));
sb.append((char) (count % 20 + 64));
final String key = exchange.getKey().reset().decodeString();
assertEquals(sb.toString(), key);
}
assertEquals(400, count);
exchange.getKey().clear().append(Key.AFTER);
for (count = 399; exchange.previous() && count > -10000; count--) {
sb.setLength(0);
sb.append((char) (count / 20 + 64));
sb.append((char) (count % 20 + 64));
final String key = exchange.getKey().reset().decodeString();
assertEquals(sb.toString(), key);
}
assertEquals(0, count);
}
@Test
public void test2() throws PersistitException {
store2();
fetch2();
}
private void store2() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1LongRecord", true);
exchange.getValue().setMaximumSize(32 * 1024 * 1024);
final StringBuilder sb = new StringBuilder();
int length = 19;
while (length < 10000000) {
sb.setLength(0);
sb.append(com.persistit.util.Util.format(length));
sb.append(" ");
sb.setLength(length);
exchange.getValue().put(sb.toString());
exchange.clear().append(length).store();
length *= 2;
}
}
private void fetch2() throws PersistitException {
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1LongRecord", true);
exchange.getValue().setMaximumSize(32 * 1024 * 1024);
final StringBuilder sb = new StringBuilder();
final StringBuilder sb2 = new StringBuilder();
int length = 19;
while (length < 10000000) {
sb.setLength(0);
sb.append(com.persistit.util.Util.format(length));
sb.append(" ");
sb.setLength(length);
// System.out.print("Record length " + length);
exchange.clear().append(length).fetch();
sb2.setLength(0);
exchange.getValue().getString(sb2);
assertEquals(sb.toString(), sb2.toString());
// System.out.println(" - read");
length *= 2;
}
}
@Test
public void test3() throws PersistitException {
// Tests fix for split calculation failure.
//
final StringBuilder sb = new StringBuilder(4000);
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1BadSplit", true);
exchange.removeAll();
final Key key = exchange.getKey();
final Value value = exchange.getValue();
key.clear().append("A").append(1);
setupString(sb, 3000);
value.putString(sb);
exchange.store();
key.clear().append("A").append(2);
setupString(sb, 3000);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1566).append(3);
setupString(sb, 119);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1568).append(4);
setupString(sb, 2258);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1569).append(3);
setupString(sb, 119);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1571).append(3);
setupString(sb, 3052);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1573).append(3);
setupString(sb, 119);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1573).append(4);
setupString(sb, 2203);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1573).append(3);
setupString(sb, 2524);
value.putString(sb);
exchange.store();
key.clear().append("stress2").append(1566).append(3);
setupString(sb, 119);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
key.clear().append("stress2").append(1568).append(4);
setupString(sb, 2258);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
key.clear().append("stress2").append(1569).append(3);
setupString(sb, 119);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
key.clear().append("stress2").append(1571).append(3);
setupString(sb, 3052);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
key.clear().append("stress2").append(1573).append(4);
setupString(sb, 2203);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
key.clear().append("stress2").append(1573).append(3);
setupString(sb, 2524);
exchange.fetch();
assertEquals(sb.toString(), exchange.getValue().getString());
}
@Test
public void test4() throws PersistitException {
// Tests join calculation.
//
final StringBuilder sb = new StringBuilder(4000);
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1BadJoin", true);
exchange.removeAll();
final Key key = exchange.getKey();
final Value value = exchange.getValue();
key.clear().append("A").append(1);
setupString(sb, 1000);
value.putString(sb);
exchange.store();
key.clear().append("A").append(2);
setupString(sb, 1000);
value.putString(sb);
exchange.store();
key.clear().append("A").append(3);
setupString(sb, 1000);
value.putString(sb);
exchange.store();
key.clear()
.append("B")
.append("... a pretty long key value. The goal is to get the the record "
+ "for this key into the penultimate slot of the left page, followed "
+ "by a short key on the edge. Then delete that short key, so that"
+ "this becomes the edge key.");
setupString(sb, 10);
value.putString(sb);
exchange.store();
// Here's where we want the page to split...
key.clear().append("B").append("z");
setupString(sb, 20);
value.putString(sb);
exchange.store();
key.clear().append("C").append(1);
setupString(sb, 1000);
value.putString(sb);
exchange.store();
key.clear().append("C").append(2);
setupString(sb, 1000);
value.putString(sb);
exchange.store();
for (int len = 1000; len < 2600; len += 100) {
key.clear().append("A").append(1);
setupString(sb, len);
value.putString(sb);
exchange.store();
key.clear().append("A").append(2);
setupString(sb, len);
value.putString(sb);
exchange.store();
key.clear().append("A").append(3);
setupString(sb, len);
value.putString(sb);
exchange.store();
key.clear().append("C").append(1);
setupString(sb, len);
value.putString(sb);
exchange.store();
}
// Now the page should be split with the {"B", "z"} on the edge.
// Need an additional 4540 bytes, leaving 60 bytes free.
key.clear().append("C").append(1);
setupString(sb, 4040); // adds 1540
value.putString(sb);
exchange.store();
key.clear().append("C").append(2);
setupString(sb, 4040); // adds 1540
value.putString(sb);
exchange.store();
key.clear().append("C").append(2);
setupString(sb, 4040); // adds 1540
value.putString(sb);
exchange.store();
key.clear().append("A").append(1);
setupString(sb, 2500 + 356);
value.putString(sb);
exchange.store();
key.clear().append("A").append(1);
exchange.fetch();
key.clear().append("B").append("z");
exchange.fetch();
key.clear().append("C").append(3);
exchange.fetch();
key.clear().append("B").append("z");
exchange.remove(); // may cause wedge failure.
}
@Test
public void test5() throws PersistitException {
final StringBuilder sb = new StringBuilder(1024 * 1024 * 16);
final StringBuilder sb2 = new StringBuilder(1024 * 1024 * 16);
final Exchange exchange = _persistit.getExchange(_volume, "TemporaryVolumeTest1BadStoreOverLengthRecord", true);
exchange.removeAll();
final Key key = exchange.getKey();
final Value value = exchange.getValue();
value.setMaximumSize(1024 * 1024 * 32);
key.clear().append("A").append(1);
final int length = 8160 * 1024 * 2 + 1;
// System.out.print(" " + length);
setupString(sb, length);
value.putString(sb);
exchange.store();
exchange.fetch();
value.getString(sb2);
final int length2 = sb2.length();
assertEquals(length, length2);
assertTrue(sb.toString().equals(sb2.toString()));
}
@Test
public void testLazyCreateFile() throws Exception {
final Exchange ex = _persistit.getExchange(_volume, "T2", true);
final FileFilter ff = new FileFilter() {
@Override
public boolean accept(final File pathname) {
return pathname.getName().contains("persistit_tempvol_");
}
};
// File should not be there
assertEquals(0, new File(_persistit.getConfiguration().getProperty("datapath")).listFiles(ff).length);
ex.getValue().put(RED_FOX);
for (int index = 0; index < 1000000; index++) {
ex.to(index).store();
}
// File should be there
assertEquals(1, new File(_persistit.getConfiguration().getProperty("datapath")).listFiles(ff).length);
}
@Test
public void testMaxSize() throws Exception {
_persistit.getConfiguration().setTmpVolMaxSize(64 * 1024 * 1024);
final Volume volume2 = _persistit.createTemporaryVolume();
final Exchange ex1 = _persistit.getExchange(_volume, "T2", true);
final Exchange ex2 = _persistit.getExchange(volume2, "T2", true);
ex1.getValue().put(RED_FOX);
ex2.getValue().put(RED_FOX);
boolean full1 = false;
boolean full2 = false;
for (int index = 0; index < 1000000; index++) {
full1 = full2 = true;
try {
ex1.to(index).store();
full1 = false;
ex2.to(index).store();
full2 = false;
} catch (final VolumeFullException e) {
assertTrue(!full1);
assertTrue(full2);
break;
}
}
}
@Test
public void testTruncate() throws Exception {
final Exchange ex = _persistit.getExchange(_volume, "T2", true);
for (int cycle = 0; cycle < 10; cycle++) {
if (cycle > 1) {
assertEquals(2, _volume.getTreeNames().length);
}
_volume.truncate();
assertEquals(0, _volume.getTreeNames().length);
store1();
ex.getValue().put(RED_FOX);
for (int i = 0; i < 1000000; i++) {
ex.to(i).store();
}
fetch1a();
}
_persistit.releaseExchange(ex);
}
@Test
public void testTruncate2() throws Exception {
final Exchange ex = _persistit.getExchange(_volume, "T2", true);
ex.getValue().put(RED_FOX);
for (int cycle = 0; cycle < 50; cycle++) {
_volume.truncate();
for (int i = 0; i < 100000; i++) {
ex.clear().append(i).store();
}
if (cycle % 10 == 0) {
System.out.print(".");
}
}
System.out.println();
_persistit.releaseExchange(ex);
}
@Test
public void testInvalidateBuffers() throws Exception {
final Exchange exchange1 = _persistit.getExchange("persistit", "TemporaryVolumeTest1", true);
final Management management = _persistit.getManagement();
final int bufferCount = management.getBufferPoolInfoArray()[0].getBufferCount();
exchange1.getValue().put(RED_FOX);
// fill up the buffer pool with valid pages.
int key;
for (key = 0;; key++) {
exchange1.to(key).store();
if (exchange1.getVolume().getNextAvailablePage() > bufferCount) {
break;
}
}
for (int cycle = 1; cycle < 10; cycle++) {
final Exchange exchange2 = _persistit.getExchange(_volume, "TemporaryVolumeTest1", true);
exchange2.getValue().put(RED_FOX);
final long startingEvictCount = management.getBufferPoolInfoArray()[0].getEvictCount();
for (int k2 = 0; k2 < (key * cycle) / 10; k2++) {
exchange2.to(k2).store();
}
final long evictions = management.getBufferPoolInfoArray()[0].getEvictCount() - startingEvictCount;
System.out.println("Cycle=" + cycle + " had " + evictions + " evictions");
assertTrue("Too many evictions in cycle " + cycle + ": " + evictions, evictions < bufferCount * 0.15);
System.out.println("Invalidating " + _volume.getNextAvailablePage() + " pages in cycle " + cycle);
_volume.truncate();
}
}
void setupString(final StringBuilder sb, final int length) {
sb.setLength(length);
final String s = "length=" + length;
sb.replace(0, s.length(), s);
for (int i = s.length(); i < length; i++) {
sb.setCharAt(i, ' ');
}
}
public static void pause(final String prompt) {
System.out.print(prompt + " Press ENTER to continue");
System.out.flush();
try {
while (System.in.read() != '\r') {
}
} catch (final IOException ioe) {
}
System.out.println();
}
public static void main(final String[] args) throws Exception {
new TemporaryVolumeTest1().initAndRunTest();
}
@Override
public Properties getProperties(final boolean cleanup) {
return UnitTestProperties.getBiggerProperties(cleanup);
}
@Override
public void runAllTests() throws Exception {
}
}