/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.graphdb;
import org.apache.commons.lang3.ArrayUtils;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import org.neo4j.collection.primitive.PrimitiveLongCollections;
import org.neo4j.io.fs.FileUtils;
import org.neo4j.kernel.NeoStoreDataSource;
import org.neo4j.kernel.api.labelscan.LabelScanStore;
import org.neo4j.kernel.api.labelscan.LabelScanWriter;
import org.neo4j.kernel.api.labelscan.NodeLabelUpdate;
import org.neo4j.kernel.impl.api.scan.LabelScanStoreProvider;
import org.neo4j.kernel.impl.transaction.state.DataSourceManager;
import org.neo4j.storageengine.api.schema.LabelScanReader;
import org.neo4j.test.rule.DatabaseRule;
import org.neo4j.test.rule.EmbeddedDatabaseRule;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class LuceneLabelScanStoreIT
{
@Rule
public final DatabaseRule dbRule = new EmbeddedDatabaseRule( getClass() );
@Test
public void scanStoreStartWithoutExistentIndex() throws IOException
{
NeoStoreDataSource dataSource = getDataSource();
LabelScanStore labelScanStore = getLabelScanStore();
labelScanStore.shutdown();
File labelScanStoreDirectory = getLabelScanStoreDirectory( dataSource );
FileUtils.deleteRecursively( labelScanStoreDirectory );
labelScanStore.init();
labelScanStore.start();
checkLabelScanStoreAccessible( labelScanStore );
}
@Test
public void scanStoreRecreateCorruptedIndexOnStartup() throws IOException
{
NeoStoreDataSource dataSource = getDataSource();
LabelScanStore labelScanStore = getLabelScanStore();
Node node = createTestNode();
long[] labels = readNodeLabels( labelScanStore, node );
assertEquals( "Label scan store see 1 label for node", 1, labels.length );
labelScanStore.force();
labelScanStore.shutdown();
corruptIndex( dataSource );
labelScanStore.init();
labelScanStore.start();
long[] rebuildLabels = readNodeLabels( labelScanStore, node );
assertArrayEquals( "Store should rebuild corrupted index", labels, rebuildLabels );
}
private long[] readNodeLabels( LabelScanStore labelScanStore, Node node )
{
try ( LabelScanReader reader = labelScanStore.newReader() )
{
return PrimitiveLongCollections.asArray( reader.labelsForNode( node.getId() ) );
}
}
private Node createTestNode()
{
Node node = null;
try (Transaction transaction = dbRule.beginTx())
{
node = dbRule.createNode( Label.label( "testLabel" ));
transaction.success();
}
return node;
}
private void corruptIndex( NeoStoreDataSource dataSource ) throws IOException
{
File labelScanStoreDirectory = getLabelScanStoreDirectory( dataSource );
Files.walkFileTree( labelScanStoreDirectory.toPath(), new SimpleFileVisitor()
{
@Override
public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException
{
Files.write( file, ArrayUtils.add(Files.readAllBytes( file ), (byte) 7 ));
return FileVisitResult.CONTINUE;
}
} );
}
private File getLabelScanStoreDirectory( NeoStoreDataSource dataSource )
{
return LabelScanStoreProvider.getStoreDirectory( dataSource.getStoreDir() );
}
private NeoStoreDataSource getDataSource()
{
DependencyResolver dependencyResolver = dbRule.getDependencyResolver();
DataSourceManager dataSourceManager = dependencyResolver.resolveDependency( DataSourceManager.class );
return dataSourceManager.getDataSource();
}
private LabelScanStore getLabelScanStore()
{
DependencyResolver dependencyResolver = dbRule.getDependencyResolver();
return dependencyResolver.resolveDependency( LabelScanStore.class );
}
private void checkLabelScanStoreAccessible( LabelScanStore labelScanStore ) throws IOException
{
try ( LabelScanWriter labelScanWriter = labelScanStore.newWriter() )
{
labelScanWriter.write( NodeLabelUpdate.labelChanges( 1, new long[]{}, new long[]{1} ) );
}
try ( LabelScanReader labelScanReader = labelScanStore.newReader() )
{
assertEquals( 1, labelScanReader.labelsForNode( 1 ).next() );
}
}
}