@Override public TransactionId getLastCommittedTransaction() { return new TransactionId( transactionId, transactionChecksum, BASE_TX_COMMIT_TIMESTAMP ); }
/** * In case if we can't find information about transaction in logs we will create new transaction * information record. * Those should be used <b>only</b> in case if we do not have any transaction logs available during * migration. * * Logs can be absent in two possible scenarios: * <ol> * <li>We do not have any logs since there were not transaction.</li> * <li>Logs are missing.</li> * </ol> * For both of those cases specific informational records will be produced. * * @param lastTransactionId last committed transaction id * @return supplier of custom id records. */ private static TransactionId specificTransactionInformationSupplier( long lastTransactionId ) { return lastTransactionId == TransactionIdStore.BASE_TX_ID ? new TransactionId( lastTransactionId, BASE_TX_CHECKSUM, BASE_TX_COMMIT_TIMESTAMP ) : new TransactionId( lastTransactionId, UNKNOWN_TX_CHECKSUM, UNKNOWN_TX_COMMIT_TIMESTAMP ); }
/** * Overrides the highest transaction id value, no matter what it currently is. Used for initialization purposes. * * @param transactionId id of the transaction. * @param checksum checksum of the transaction. * @param commitTimestamp commit time for transaction with {@code transactionId}. */ public final void set( long transactionId, long checksum, long commitTimestamp ) { highest.set( new TransactionId( transactionId, checksum, commitTimestamp ) ); }
@Override public TransactionId getUpgradeTransaction() { return new TransactionId( previouslyCommittedTxId, initialTransactionChecksum, previouslyCommittedTxCommitTimestamp ); }
TransactionId readLastTxInformation( DatabaseLayout migrationStructure ) throws IOException { long[] counters = readTxLogCounters( fileSystem, lastTxInformationFile( migrationStructure ), 3 ); return new TransactionId( counters[0], counters[1], counters[2] ); }
/** * Offers a transaction id. Will be accepted if this is higher than the current highest. * This method is thread-safe. * * @param transactionId transaction id to compare for highest. * @param checksum checksum of the transaction. * @param commitTimestamp commit time for transaction with {@code transactionId}. * @return {@code true} if the given transaction id was higher than the current highest, * {@code false}. */ public boolean offer( long transactionId, long checksum, long commitTimestamp ) { TransactionId high = highest.get(); if ( transactionId < high.transactionId() ) { // a higher id has already been offered return false; } TransactionId update = new TransactionId( transactionId, checksum, commitTimestamp ); while ( !highest.compareAndSet( high, update ) ) { high = highest.get(); if ( high.transactionId() >= transactionId ) { // apparently someone else set a higher id while we were trying to set this id return false; } } // we set our id as the highest return true; }
@Override public synchronized void transactionCommitted( long transactionId, long checksum, long commitTimestamp ) { TransactionId current = committedTransactionId.get(); if ( current == null || transactionId > current.transactionId() ) { committedTransactionId.set( new TransactionId( transactionId, checksum, commitTimestamp ) ); } }
@Override public void setLastCommittedAndClosedTransactionId( long transactionId, long checksum, long commitTimestamp, long byteOffset, long logVersion ) { committingTransactionId.set( transactionId ); committedTransactionId.set( new TransactionId( transactionId, checksum, commitTimestamp ) ); closedTransactionId.set( transactionId, new long[]{logVersion, byteOffset} ); }
TransactionId extractTransactionIdInformation( File neoStore, long lastTransactionId ) throws IOException { long checksum = MetaDataStore.getRecord( pageCache, neoStore, Position.LAST_TRANSACTION_CHECKSUM ); long commitTimestamp = MetaDataStore.getRecord( pageCache, neoStore, Position.LAST_TRANSACTION_COMMIT_TIMESTAMP ); if ( checksum != FIELD_NOT_PRESENT && commitTimestamp != FIELD_NOT_PRESENT ) { return new TransactionId( lastTransactionId, checksum, commitTimestamp ); } return specificTransactionInformationSupplier( lastTransactionId ); }
@Test public void shouldHardSetHighest() { // GIVEN HighestTransactionId highest = new HighestTransactionId( 10, 10, 10 ); // WHEN highest.set( 8, 1299128, 42 ); // THEN assertEquals( new TransactionId( 8, 1299128, 42 ), highest.get() ); }
private static KernelTransactions newKernelTransactions( Locks locks, StorageEngine storageEngine, TransactionCommitProcess commitProcess, boolean testKernelTransactions ) { LifeSupport life = new LifeSupport(); life.start(); TransactionIdStore transactionIdStore = mock( TransactionIdStore.class ); when( transactionIdStore.getLastCommittedTransaction() ).thenReturn( new TransactionId( 0, 0, 0 ) ); Tracers tracers = new Tracers( "null", NullLog.getInstance(), new Monitors(), mock( JobScheduler.class ), clock ); StatementLocksFactory statementLocksFactory = new SimpleStatementLocksFactory( locks ); StatementOperationParts statementOperations = mock( StatementOperationParts.class ); KernelTransactions transactions; if ( testKernelTransactions ) { transactions = createTestTransactions( storageEngine, commitProcess, transactionIdStore, tracers, statementLocksFactory, statementOperations, clock, databaseAvailabilityGuard ); } else { transactions = createTransactions( storageEngine, commitProcess, transactionIdStore, tracers, statementLocksFactory, statementOperations, clock, databaseAvailabilityGuard ); } transactions.start(); return transactions; }
public void setUpgradeTransaction( long id, long checksum, long timestamp ) { long pageId = pageIdForRecord( Position.UPGRADE_TRANSACTION_ID.id ); assert pageId == pageIdForRecord( Position.UPGRADE_TRANSACTION_CHECKSUM.id ); synchronized ( upgradeTransactionLock ) { try ( PageCursor cursor = pagedFile.io( pageId, PF_SHARED_WRITE_LOCK ) ) { if ( !cursor.next() ) { throw new UnderlyingStorageException( "Could not access MetaDataStore page " + pageId ); } setRecord( cursor, Position.UPGRADE_TRANSACTION_ID, id ); setRecord( cursor, Position.UPGRADE_TRANSACTION_CHECKSUM, checksum ); setRecord( cursor, Position.UPGRADE_TRANSACTION_COMMIT_TIMESTAMP, timestamp ); upgradeTxIdField = id; upgradeTxChecksumField = checksum; upgradeCommitTimestampField = timestamp; upgradeTransaction = new TransactionId( id, checksum, timestamp ); } catch ( IOException e ) { throw new UnderlyingStorageException( e ); } } }
@Test public void shouldExtractTransactionInformationFromMetaDataStore() throws Exception { // given // ... variables long txId = 42; long checksum = 123456789123456789L; long timestamp = 919191919191919191L; TransactionId expected = new TransactionId( txId, checksum, timestamp ); // ... and files DatabaseLayout databaseLayout = directory.databaseLayout(); File neoStore = databaseLayout.metadataStore(); neoStore.createNewFile(); // ... and mocks Config config = mock( Config.class ); LogService logService = mock( LogService.class ); // when // ... data in record setRecord( pageCache, neoStore, LAST_TRANSACTION_ID, txId ); setRecord( pageCache, neoStore, LAST_TRANSACTION_CHECKSUM, checksum ); setRecord( pageCache, neoStore, LAST_TRANSACTION_COMMIT_TIMESTAMP, timestamp ); // ... and with migrator StoreMigrator migrator = new StoreMigrator( fileSystemRule.get(), pageCache, config, logService, jobScheduler ); TransactionId actual = migrator.extractTransactionIdInformation( neoStore, txId ); // then assertEquals( expected, actual ); }
BASE_TX_COMMIT_TIMESTAMP ); upgradeTransaction = new TransactionId( upgradeTxIdField, upgradeTxChecksumField, upgradeCommitTimestampField );
@Test public void writeAndReadLastTxInformation() throws IOException { StoreMigrator migrator = newStoreMigrator(); TransactionId writtenTxId = new TransactionId( random.nextLong(), random.nextLong(), random.nextLong() ); migrator.writeLastTxInformation( directory.databaseLayout(), writtenTxId ); TransactionId readTxId = migrator.readLastTxInformation( directory.databaseLayout() ); assertEquals( writtenTxId, readTxId ); }
@Test public void shouldSetHighestTransactionIdWhenNeeded() { // GIVEN FileSystemAbstraction fileSystem = fs.get(); StoreFactory factory = getStoreFactory( Config.defaults(), databaseLayout, fileSystem, LOG_PROVIDER ); try ( NeoStores neoStore = factory.openAllNeoStores( true ) ) { MetaDataStore store = neoStore.getMetaDataStore(); store.setLastCommittedAndClosedTransactionId( 40, 4444, BASE_TX_COMMIT_TIMESTAMP, LogHeader.LOG_HEADER_SIZE, 0 ); // WHEN store.transactionCommitted( 42, 6666, BASE_TX_COMMIT_TIMESTAMP ); // THEN assertEquals( new TransactionId( 42, 6666, BASE_TX_COMMIT_TIMESTAMP ), store.getLastCommittedTransaction() ); assertArrayEquals( store.getLastClosedTransaction(), new long[]{40,0,LogHeader.LOG_HEADER_SIZE} ); } }
@Test public void shouldNotSetHighestTransactionIdWhenNeeded() { // GIVEN FileSystemAbstraction fileSystem = fs.get(); StoreFactory factory = getStoreFactory( Config.defaults(), databaseLayout, fileSystem, LOG_PROVIDER ); try ( NeoStores neoStore = factory.openAllNeoStores( true ) ) { MetaDataStore store = neoStore.getMetaDataStore(); store.setLastCommittedAndClosedTransactionId( 40, 4444, BASE_TX_COMMIT_TIMESTAMP, LogHeader.LOG_HEADER_SIZE, 0 ); // WHEN store.transactionCommitted( 39, 3333, BASE_TX_COMMIT_TIMESTAMP ); // THEN assertEquals( new TransactionId( 40, 4444, BASE_TX_COMMIT_TIMESTAMP ), store.getLastCommittedTransaction() ); assertArrayEquals( store.getLastClosedTransaction(), new long[]{40,0,LogHeader.LOG_HEADER_SIZE} ); } }
assertEquals( 8, metaDataStore.getGraphNextProp() ); assertEquals( 9, metaDataStore.getLatestConstraintIntroducingTx() ); assertEquals( new TransactionId( 10, 11, BASE_TX_COMMIT_TIMESTAMP ), metaDataStore.getUpgradeTransaction() ); assertEquals( 12, metaDataStore.getUpgradeTime() ); assertEquals( new TransactionId( 10, 11, 13 ), metaDataStore.getUpgradeTransaction() );
/** * Overrides the highest transaction id value, no matter what it currently is. Used for initialization purposes. * * @param transactionId id of the transaction. * @param checksum checksum of the transaction. * @param commitTimestamp commit time for transaction with {@code transactionId}. */ public final void set( long transactionId, long checksum, long commitTimestamp ) { highest.set( new TransactionId( transactionId, checksum, commitTimestamp ) ); }
TransactionId readLastTxInformation( DatabaseLayout migrationStructure ) throws IOException { long[] counters = readTxLogCounters( fileSystem, lastTxInformationFile( migrationStructure ), 3 ); return new TransactionId( counters[0], counters[1], counters[2] ); }