/**
* Copyright 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.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import org.junit.Test;
import com.persistit.BufferPool.BufferHolder;
public class BufferPoolTest extends PersistitUnitTestCase {
/**
* Covers allocPage condition in which page in the avaialbleBitMap is
* unavailable.
*
* @throws Exception
*/
@Test
public void testInvalidatedBuffers() throws Exception {
final Volume vol = _persistit.createTemporaryVolume();
final Exchange ex = _persistit.getExchange(vol, "BufferPoolTest", true);
ex.append("k").store();
// Hold a claim on the page.
final Buffer buffer1 = vol.getPool().get(vol, 2, false, true);
buffer1.release();
// Invalidate the buffers
vol.getPool().invalidate(vol);
// reestablish claim on now-invalid buffer
buffer1.claim(true, 0);
// Do work that allocates buffers
final Exchange ex2 = _persistit.getExchange("persistit", "BufferPoolTest", true);
ex2.getValue().put(RED_FOX);
for (int i = 0; i < 10000; i++) {
ex2.to(i).store();
}
buffer1.release();
}
@Test
public void testSelectDirtyBuffers() throws Exception {
final Volume volume = _persistit.getVolume("persistit");
final BufferPool pool = volume.getPool();
pool.setFlushTimestamp(-1);
try {
final int buffers = pool.getBufferCount();
final int[] priorities = new int[buffers / 2];
final BufferHolder[] holders = new BufferHolder[buffers / 2];
for (int i = 0; i < holders.length; i++) {
holders[i] = new BufferHolder();
}
final long timestamp = _persistit.getTimestampAllocator().getCurrentTimestamp();
pool.flush(timestamp);
int count = pool.selectDirtyBuffers(priorities, holders);
assertEquals("Buffer pool should be clean", 0, count);
for (int i = 1; i < buffers; i++) {
final long page = volume.getStorage().allocNewPage();
final Buffer buffer = pool.get(volume, page, true, false);
buffer.setDirtyAtTimestamp(timestamp + i);
buffer.releaseTouched();
}
count = pool.selectDirtyBuffers(priorities, holders);
assertEquals("Selected buffers should fill the arrays", buffers / 2, count);
long page = -1;
Arrays.sort(holders);
for (final BufferHolder holder : holders) {
assertTrue(holder.getPage() > page);
page = holder.getPage();
}
} finally {
pool.setFlushTimestamp(1000);
}
}
@Test
public void testAddSelectedBuffer() throws Exception {
final Volume volume = _persistit.getVolume("persistit");
final BufferPool pool = volume.getPool();
final int total = 100;
final int[] priorities = new int[total];
final BufferHolder[] holders = new BufferHolder[total];
for (int i = 0; i < holders.length; i++) {
holders[i] = new BufferHolder();
}
final Random random = new Random(1);
final SortedSet<Integer> sorted = new TreeSet<Integer>();
int count = 0;
for (int index = 0; index < 10000; index++) {
final int r = random.nextInt(1000000000);
if (sorted.contains(r)) {
index--;
continue;
}
sorted.add(r);
final Buffer buffer = pool.get(volume, 1, false, false);
final Buffer copy = new Buffer(buffer);
copy.setPageAddressAndVolume(index, volume);
count = pool.addSelectedBufferByPriority(copy, r, priorities, holders, count);
buffer.release();
}
assertEquals("Arrays should be full", total, count);
final Integer[] sortedArray = sorted.toArray(new Integer[sorted.size()]);
for (int i = 0; i < count; i++) {
final int s = sortedArray[sortedArray.length - i - 1];
final int r = priorities[i];
assertEquals("Priority order is wrong", s, r);
}
long page = -1;
Arrays.sort(holders);
for (final BufferHolder holder : holders) {
assertTrue(holder.getPage() > page);
page = holder.getPage();
}
for (int i = 0; i < count; i++) {
final BufferHolder holder = holders[i];
for (int j = i + 1; j < count; j++) {
assertTrue("Scrambled holders", holder != holders[j]);
}
}
}
@Test
public void testWritePriority() throws Exception {
final long m = 100 * 1000 * 1000;
final Volume volume = _persistit.getVolume("persistit");
final BufferPool pool = volume.getPool();
final Buffer buffer = pool.getBufferCopy(0);
buffer.claim(true);
long currentTimestamp = 4 * m;
final long checkpointTimestamp = 2 * m;
for (long timestamp = m; timestamp < m * 20; timestamp += m) {
buffer.setDirtyAtTimestamp(timestamp);
final int priority = pool.writePriority(buffer, 123456, checkpointTimestamp, currentTimestamp);
System.out.printf("Timestamp %,15d Checkpoint %,15d Current %,15d Priority %,15d\n", timestamp,
checkpointTimestamp, currentTimestamp, priority);
currentTimestamp += 10000000;
}
}
@Test
public void testEvictVoume() throws Exception {
final Volume vol = _persistit.createTemporaryVolume();
final Exchange ex = _persistit.getExchange(vol, "BufferPoolTest", true);
_persistit.flush();
ex.getValue().put(RED_FOX);
int i;
for (i = 1;; i++) {
ex.to(i).store();
if (vol.getNextAvailablePage() >= 10) {
break;
}
}
vol.getPool().evict(vol);
assertTrue("Should be no remaining dirty buffers", vol.getPool().getDirtyPageCount() == 0);
for (int j = 0; j < i + 100; j++) {
ex.to(j).fetch();
assertEquals(j >= 1 && j <= i, ex.getValue().isDefined());
}
}
}