/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002-2005
* Sleepycat Software. All rights reserved.
*
* $Id: LogBufferPoolTest.java,v 1.53 2005/09/23 19:14:53 mark Exp $
*/
package com.sleepycat.je.log;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.utilint.DbLsn;
import com.sleepycat.je.util.TestUtils;
public class LogBufferPoolTest extends TestCase {
static private final boolean DEBUG = false;
Environment env;
Database db;
EnvironmentImpl environment;
FileManager fileManager;
File envHome;
LogBufferPool bufPool;
public LogBufferPoolTest() {
super();
envHome = new File(System.getProperty(TestUtils.DEST_DIR));
}
protected void setUp()
throws Exception {
/* Remove files to start with a clean slate. */
TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
}
protected void tearDown()
throws Exception {
bufPool = null;
if (fileManager != null) {
fileManager.clear();
fileManager.close();
}
TestUtils.removeFiles("TearDown", envHome, FileManager.JE_SUFFIX);
}
/**
* Make sure that we'll add more buffers as needed.
*/
public void testGrowBuffers()
throws Throwable {
try {
setupEnv(true);
/*
* Each buffer can only hold 2 items. Put enough test items in to
* get seven buffers.
*/
List lsns = new ArrayList();
for (int i = 0; i < 14; i++) {
long lsn = insertData(bufPool, (byte)(i + 1));
lsns.add(new Long(lsn));
}
/*
* Check that the bufPool knows where each LSN lives and that the
* fetched buffer does hold this item.
*/
LogBuffer logBuf;
ByteBuffer b;
for (int i = 0; i < 14; i++) {
/*
* For each test LSN, ask the bufpool for the logbuffer that
* houses it.
*/
long testLsn = DbLsn.longToLsn((Long) lsns.get(i));
logBuf = bufPool.getReadBuffer(testLsn);
assertNotNull(logBuf);
/* Here's the expected data. */
byte[] expected = new byte[10];
Arrays.fill(expected, (byte)(i+1));
/* Here's the data in the log buffer. */
byte[] logData = new byte[10];
b = logBuf.getDataBuffer();
long firstLsnInBuf = logBuf.getFirstLsn();
b.position((int) (DbLsn.getFileOffset(testLsn) -
DbLsn.getFileOffset(firstLsnInBuf)));
logBuf.getDataBuffer().get(logData);
/* They'd better be equal. */
assertTrue(Arrays.equals(logData, expected));
logBuf.release();
}
/*
* This LSN shouldn't be in the buffers, it's less than any
* buffered item.
*/
assertNull(bufPool.getReadBuffer(DbLsn.makeLsn(0,10)));
/*
* This LSN is illegal to ask for, it's greater than any registered
* LSN.
*/
assertNull("LSN too big",
bufPool.getReadBuffer(DbLsn.makeLsn(10, 141)));
} catch (Throwable t) {
t.printStackTrace();
throw t;
}
}
/**
* Helper to insert fake data.
* @return LSN registered for this fake data
*/
private long insertData(LogBufferPool bufPool,
byte value)
throws IOException, DatabaseException {
byte[] data = new byte[10];
Arrays.fill(data, value);
boolean flippedFile = fileManager.bumpLsn(data.length);
ByteBuffer logBuf = bufPool.getWriteBuffer(data.length, flippedFile);
logBuf.put(data);
long lsn = fileManager.getLastUsedLsn();
bufPool.writeCompleted(fileManager.getLastUsedLsn(), false);
return lsn;
}
/**
* Test buffer flushes.
*/
public void testBufferFlush()
throws Throwable {
try {
setupEnv(false);
assertFalse("There should be no files", fileManager.filesExist());
/*
* Each buffer can only hold 2 items. Put enough test items in to
* get five buffers.
*/
/* CWL: What is lsnList used for? */
List lsnList = new ArrayList();
for (int i = 0; i < 9; i++) {
long lsn = insertData(bufPool, (byte)(i+1));
lsnList.add(new Long(lsn));
}
bufPool.writeBufferToFile(0);
fileManager.syncLogEnd();
/* We should see two files exist. */
String[] fileNames =
fileManager.listFiles(FileManager.JE_SUFFIXES);
assertEquals("Should be 2 files", 2, fileNames.length);
/* Read the files. */
if (false) {
ByteBuffer dataBuffer = ByteBuffer.allocate(100);
FileHandle file0 = fileManager.getFileHandle(0L);
RandomAccessFile file = file0.getFile();
FileChannel channel = file.getChannel();
int bytesRead = channel.read(dataBuffer,
FileManager.firstLogEntryOffset());
dataBuffer.flip();
assertEquals("Check bytes read", 50, bytesRead);
assertEquals("Check size of file", 50, dataBuffer.limit());
file.close();
FileHandle file1 = fileManager.getFileHandle(1L);
file = file1.getFile();
channel = file.getChannel();
bytesRead = channel.read(dataBuffer,
FileManager.firstLogEntryOffset());
dataBuffer.flip();
assertEquals("Check bytes read", 40, bytesRead);
assertEquals("Check size of file", 40, dataBuffer.limit());
file0.release();
file1.release();
}
} catch (Throwable e) {
e.printStackTrace();
throw e;
}
}
public void testTemporaryBuffers()
throws Exception {
final int KEY_SIZE = 10;
final int DATA_SIZE = 1000000;
tempBufferInitEnvInternal
("0", MemoryBudget.MIN_MAX_MEMORY_SIZE_STRING);
DatabaseEntry key = new DatabaseEntry(new byte[KEY_SIZE]);
DatabaseEntry data = new DatabaseEntry(new byte[DATA_SIZE]);
db.put(null, key, data);
db.close();
env.close();
}
private void tempBufferInitEnvInternal(String buffSize, String cacheSize)
throws DatabaseException {
EnvironmentConfig envConfig = TestUtils.initEnvConfig();
envConfig.setTransactional(true);
envConfig.setAllowCreate(true);
if (!buffSize.equals("0")) {
envConfig.setConfigParam("je.log.totalBufferBytes", buffSize);
}
if (!cacheSize.equals("0")) {
envConfig.setConfigParam("je.maxMemory", cacheSize);
}
env = new Environment(new File("."), envConfig);
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(true);
dbConfig.setTransactional(true);
db = env.openDatabase(null, "InsertAndDelete", dbConfig);
}
private void setupEnv(boolean inMemory)
throws Exception {
EnvironmentConfig envConfig = TestUtils.initEnvConfig();
DbInternal.disableParameterValidation(envConfig);
envConfig.setConfigParam(EnvironmentParams.LOG_MEM_SIZE.getName(),
EnvironmentParams.LOG_MEM_SIZE_MIN_STRING);
envConfig.setConfigParam
(EnvironmentParams.LOG_FILE_MAX.getName(), "90");
envConfig.setConfigParam
(EnvironmentParams.NUM_LOG_BUFFERS.getName(), "2");
envConfig.setAllowCreate(true);
if (inMemory) {
/* Make the bufPool grow some buffers. Disable writing. */
envConfig.setConfigParam
(EnvironmentParams.LOG_MEMORY_ONLY.getName(), "true");
}
environment = new EnvironmentImpl(envHome, envConfig);
/* Make a standalone file manager for this test. */
environment.close();
environment.open(); /* Just sets state to OPEN. */
fileManager = new FileManager(environment, envHome, false);
bufPool = new LogBufferPool(fileManager, environment);
/*
* Remove any files after the environment is created again! We want to
* remove the files made by recovery, so we can test the file manager
* in controlled cases.
*/
TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
}
}