public boolean storeFilesUpgradeable(File neoStoreFile) { File storeDirectory = neoStoreFile.getParentFile(); for (String fileName : fileNamesToExpectedVersions.keySet()) { String expectedVersion = fileNamesToExpectedVersions.get(fileName); FileChannel fileChannel = null; byte[] expectedVersionBytes = UTF8.encode(expectedVersion); try { File storeFile = new File(storeDirectory, fileName); if (!fs.fileExists(storeFile)) { return false; } fileChannel = fs.open(storeFile, "r"); if (fileChannel.size() < expectedVersionBytes.length) { return false; } fileChannel.position(fileChannel.size() - expectedVersionBytes.length); byte[] foundVersionBytes = new byte[expectedVersionBytes.length]; fileChannel.read(ByteBuffer.wrap(foundVersionBytes)); if (!expectedVersion.equals(UTF8.decode(foundVersionBytes))) { return false; } } catch (IOException e) { throw new RuntimeException(e); } finally { if (fileChannel != null) { try { fileChannel.close(); } catch (IOException e) { // Ignore exception on close } } } } return true; }
private File fixPath(File dir, StoreFactory sf) { try { fileSystem.mkdirs(dir); } catch (IOException e) { throw new UnderlyingStorageException( "Unable to create directory path[" + storeDir + "] for Neo4j kernel store."); } File store = new File(dir, NeoStore.DEFAULT_NAME); if (!fileSystem.fileExists(store)) { sf.createNeoStore(store).close(); } return store; }
private int getFileSizeMb(String file) { long length = fs.getFileSize(new File(dbPath, "neostore." + file)); int mb = (int) (length / 1024 / 1024); if (mb > 0) { return mb; } // default return 1MB if small or empty file return 1; }
private void changeActiveLog(String newFileName) throws IOException { // change active log FileChannel fc = fileSystem.open(logSwitcherFileName, "rw"); ByteBuffer buf = ByteBuffer.wrap(UTF8.encode(newFileName)); fc.truncate(0); fc.write(buf); fc.force(true); fc.close(); msgLog.logMessage("Active txlog set to " + newFileName, true); }
private int logCount() { XaLogicalLog log = neoDataSource().getXaContainer().getLogicalLog(); int count = 0; for (long i = log.getHighestLogVersion() - 1; i >= 0; i--) { if (fs.fileExists(log.getFileName(i))) { count++; } else { break; } } return count; }
@Override public void init() { txThreadMap = new ArrayMap<Thread, TransactionImpl>((byte) 5, true, true); logSwitcherFileName = txLogDir + separator + "active_tx_log"; txLog1FileName = "tm_tx_log.1"; txLog2FileName = "tm_tx_log.2"; try { if (fileSystem.fileExists(logSwitcherFileName)) { FileChannel fc = fileSystem.open(logSwitcherFileName, "rw"); byte fileName[] = new byte[256]; ByteBuffer buf = ByteBuffer.wrap(fileName); fc.read(buf); fc.close(); String currentTxLog = txLogDir + separator + UTF8.decode(fileName).trim(); if (!fileSystem.fileExists(currentTxLog)) { throw logAndReturn( "TM startup failure", new TransactionFailureException( "Unable to start TM, " + "active tx log file[" + currentTxLog + "] not found.")); } txLog = new TxLog(currentTxLog, fileSystem, msgLog); msgLog.logMessage("TM opening log: " + currentTxLog, true); } else { if (fileSystem.fileExists(txLogDir + separator + txLog1FileName) || fileSystem.fileExists(txLogDir + separator + txLog2FileName)) { throw logAndReturn( "TM startup failure", new TransactionFailureException( "Unable to start TM, " + "no active tx log file found but found either " + txLog1FileName + " or " + txLog2FileName + " file, please set one of them as active or " + "remove them.")); } ByteBuffer buf = ByteBuffer.wrap(txLog1FileName.getBytes("UTF-8")); FileChannel fc = fileSystem.open(logSwitcherFileName, "rw"); fc.write(buf); txLog = new TxLog(txLogDir + separator + txLog1FileName, fileSystem, msgLog); msgLog.logMessage("TM new log: " + txLog1FileName, true); fc.force(true); fc.close(); } tmOk = true; } catch (IOException e) { log.log(Level.SEVERE, "Unable to start TM", e); throw logAndReturn( "TM startup failure", new TransactionFailureException("Unable to start TM", e)); } }
@Test public void pruneByFileSize() throws Exception { // Given int size = 1050; newDb(size + " size"); doTransaction(); rotate(); long sizeOfOneLog = fs.getFileSize(neoDataSource().getXaContainer().getLogicalLog().getFileName(0)); int filesNeededToExceedPruneLimit = (int) Math.ceil((double) size / (double) sizeOfOneLog); // When for (int i = 1; i < filesNeededToExceedPruneLimit * 2; i++) { doTransaction(); rotate(); // Then assertEquals(Math.min(i + 1, filesNeededToExceedPruneLimit), logCount()); } }
@Test public void shouldNotReadExcessivelyFromTheFileChannelWhenRotatingLogWithNoOpenTransactions() throws Exception { // given XaTransactionFactory xaTf = mock(XaTransactionFactory.class); when(xaTf.getAndSetNewVersion()).thenAnswer(new TxVersion(TxVersion.UPDATE_AND_GET)); when(xaTf.getCurrentVersion()).thenAnswer(new TxVersion(TxVersion.GET)); // spy on the file system abstraction so that we can spy on the file channel for the logical log FileSystemAbstraction fs = spy(ephemeralFs.get()); File dir = TargetDirectory.forTest(fs, XaLogicalLogTest.class).directory("log", true); // -- when opening the logical log, spy on the file channel we return and count invocations to // channel.read(*) when(fs.open(new File(dir, "logical.log.1"), "rw")) .thenAnswer( new Answer<FileChannel>() { @Override public FileChannel answer(InvocationOnMock invocation) throws Throwable { FileChannel channel = (FileChannel) invocation.callRealMethod(); return mock( channel.getClass(), withSettings() .spiedInstance(channel) .name("channel") .defaultAnswer(CALLS_REAL_METHODS) .invocationListeners( new InvocationListener() { @Override public void reportInvocation( MethodInvocationReport methodInvocationReport) { if (methodInvocationReport .getInvocation() .toString() .startsWith("channel.read(")) { reads++; } } })); } }); XaLogicalLog xaLogicalLog = new XaLogicalLog( new File(dir, "logical.log"), mock(XaResourceManager.class), mock(XaCommandFactory.class), xaTf, new DefaultLogBufferFactory(), fs, new SingleLoggingService(StringLogger.wrap(output.writer())), LogPruneStrategies.NO_PRUNING, mock(TransactionStateFactory.class), 25 * 1024 * 1024); xaLogicalLog.open(); // -- set the log up with 10 transactions (with no commands, just start and commit) for (int txId = 1; txId <= 10; txId++) { int identifier = xaLogicalLog.start(new XidImpl(XidImpl.getNewGlobalId(), RESOURCE_ID), -1, 0); xaLogicalLog.writeStartEntry(identifier); xaLogicalLog.commitOnePhase(identifier, txId, ForceMode.forced); xaLogicalLog.done(identifier); } // when xaLogicalLog.rotate(); // then assertThat( "should not read excessively from the logical log file channel", reads, lessThan(10)); }