/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.activemq.leveldb.test;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.MessageId;
import org.apache.activemq.leveldb.LevelDBStore;
import org.apache.activemq.leveldb.LevelDBStoreView;
import org.apache.activemq.leveldb.util.FileSupport;
import org.apache.activemq.store.MessageStore;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.activemq.leveldb.test.ReplicationTestSupport.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class IndexRebuildTest {
protected static final Logger LOG = LoggerFactory.getLogger(IndexRebuildTest.class);
final int max = 30;
final int toLeave = 5;
ArrayList<LevelDBStore> stores = new ArrayList<LevelDBStore>();
@Test(timeout = 1000 * 60 * 10)
public void testRebuildIndex() throws Exception {
File masterDir = new File("target/activemq-data/leveldb-rebuild");
FileSupport.toRichFile(masterDir).recursiveDelete();
final LevelDBStore store = new LevelDBStore();
store.setDirectory(masterDir);
store.setLogDirectory(masterDir);
store.setLogSize(1024 * 10);
store.start();
stores.add(store);
ArrayList<MessageId> inserts = new ArrayList<MessageId>();
MessageStore ms = store.createQueueMessageStore(new ActiveMQQueue("TEST"));
for (int i = 0; i < max; i++) {
inserts.add(addMessage(ms, "m" + i).getMessageId());
}
int logFileCount = countLogFiles(store);
assertTrue("more than one journal file", logFileCount > 1);
for (MessageId id : inserts.subList(0, inserts.size() - toLeave)) {
removeMessage(ms, id);
}
LevelDBStoreView view = new LevelDBStoreView(store);
view.compact();
int reducedLogFileCount = countLogFiles(store);
assertTrue("log files deleted", logFileCount > reducedLogFileCount);
store.stop();
deleteTheIndex(store);
assertEquals("log files remain", reducedLogFileCount, countLogFiles(store));
// restart, recover and verify message read
store.start();
ms = store.createQueueMessageStore(new ActiveMQQueue("TEST"));
assertEquals(toLeave + " messages remain", toLeave, getMessages(ms).size());
}
private void deleteTheIndex(LevelDBStore store) throws IOException {
for (String index : store.getLogDirectory().list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
LOG.info("dir:" + dir + ", name: " + name);
return (name != null && name.endsWith(".index"));
}
})) {
File file = new File(store.getLogDirectory().getAbsoluteFile(), index);
LOG.info("Deleting index directory:" + file);
FileUtils.deleteDirectory(file);
}
}
private int countLogFiles(LevelDBStore store) {
return store.getLogDirectory().list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
LOG.info("dir:" + dir + ", name: " + name);
return (name != null && name.endsWith(".log"));
}
}).length;
}
@After
public void stop() throws Exception {
for (LevelDBStore store : stores) {
if (store.isStarted()) {
store.stop();
}
FileUtils.deleteDirectory(store.directory());
}
stores.clear();
}
}