/**
* 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.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import com.persistit.JournalManager.TreeDescriptor;
import com.persistit.exception.PersistitException;
import com.persistit.exception.TreeNotFoundException;
import com.persistit.unit.UnitTestProperties;
public class TreeLifetimeTest extends PersistitUnitTestCase {
private static final String TREE_NAME = "tree_one";
private Volume getVolume() {
return _persistit.getVolume(UnitTestProperties.VOLUME_NAME);
}
private Exchange getExchange(final boolean create) throws PersistitException {
return _persistit.getExchange(getVolume(), TREE_NAME, create);
}
@Test
public void testRemovedTreeGoesToGarbageChainNoTxn() throws PersistitException {
Exchange ex = getExchange(true);
for (int i = 0; i < 5; ++i) {
ex.clear().append(i).getValue().clear().put(i);
ex.store();
}
_persistit.releaseExchange(ex);
ex = null;
ex = getExchange(false);
final long treeRoot = ex.getTree().getRootPageAddr();
ex.removeTree();
_persistit.releaseExchange(ex);
ex = null;
_persistit.cleanup();
final List<Long> garbage = getVolume().getStructure().getGarbageList();
assertTrue("Expected tree root <" + treeRoot + "> in garbage list <" + garbage.toString() + ">",
garbage.contains(treeRoot));
}
@Test
public void testRemovedTreeGoesToGarbageChainTxn() throws PersistitException {
final Transaction txn = _persistit.getTransaction();
Exchange ex;
txn.begin();
ex = getExchange(true);
for (int i = 0; i < 5; ++i) {
ex.clear().append(i).getValue().clear().put(i);
ex.store();
}
txn.commit();
txn.end();
_persistit.releaseExchange(ex);
ex = null;
txn.begin();
ex = getExchange(false);
final long treeRoot = ex.getTree().getRootPageAddr();
ex.removeTree();
txn.commit();
txn.end();
_persistit.releaseExchange(ex);
ex = null;
_persistit.cleanup();
final List<Long> garbage = getVolume().getStructure().getGarbageList();
assertTrue("Expected tree root <" + treeRoot + "> in garbage list <" + garbage.toString() + ">",
garbage.contains(treeRoot));
}
@Test
public void testGetTreeWithoutCreateShouldCreate() throws PersistitException {
final Transaction txn = _persistit.getTransaction();
txn.begin();
try {
getExchange(false);
fail("Tree should not have existed!");
} catch (final TreeNotFoundException e) {
// expected
}
final Volume volume = getVolume();
// Check on disk
final List<String> treeNames = Arrays.asList(volume.getTreeNames());
assertFalse("Tree <" + TREE_NAME + "> should not be in Volume list <" + treeNames + ">",
treeNames.contains(TREE_NAME));
// Check in-memory
assertFalse("Volume should not know about tree", volume.getStructure().treeMapContainsName(TREE_NAME));
assertEquals("Journal should not have handle for tree", -1,
_persistit.getJournalManager().handleForTree(new TreeDescriptor(volume.getHandle(), TREE_NAME), false));
txn.commit();
txn.end();
}
@Test
public void testCleanupManagerShouldNotInstantiateTrees() throws Exception {
Exchange ex = getExchange(true);
_persistit.releaseExchange(ex);
assertNotNull("Tree should exist after create", getVolume().getTree(TREE_NAME, false));
ex = getExchange(false);
final int treeHandle = ex.getTree().getHandle();
final long rootPage = ex.getTree().getRootPageAddr();
ex.removeTree();
_persistit.releaseExchange(ex);
assertNull("Tree should not exist after remove", getVolume().getTree(TREE_NAME, false));
final CleanupManager cm = _persistit.getCleanupManager();
final boolean accepted = cm.offer(new CleanupManager.CleanupPruneAction(treeHandle, rootPage));
assertTrue("CleanupPruneAction was accepted", accepted);
cm.kick();
while (cm.getEnqueuedCount() > 0) {
Thread.sleep(50);
}
assertNull("Tree should not exist after cleanup action", getVolume().getTree(TREE_NAME, false));
}
}