示例#1
0
        /// <summary>
        /// Rotates the current log file, continuing into next (version) log file.
        /// This method must be recovery safe, which means a crash at any point should be recoverable.
        /// Concurrent readers must also be able to parry for concurrent rotation.
        /// Concurrent writes will not be an issue since rotation and writing contends on the same monitor.
        ///
        /// Steps during rotation are:
        /// <ol>
        /// <li>1: Increment log version, <seealso cref="LogVersionRepository.incrementAndGetVersion()"/> (also flushes the store)</li>
        /// <li>2: Flush current log</li>
        /// <li>3: Create new log file</li>
        /// <li>4: Write header</li>
        /// </ol>
        ///
        /// Recovery: what happens if crash between:
        /// <ol>
        /// <li>1-2: New log version has been set, starting the writer will create the new log file idempotently.
        /// At this point there may have been half-written transactions in the previous log version,
        /// although they haven't been considered committed and so they will be truncated from log during recovery</li>
        /// <li>2-3: New log version has been set, starting the writer will create the new log file idempotently.
        /// At this point there may be complete transactions in the previous log version which may not have been
        /// acknowledged to be committed back to the user, but will be considered committed anyway.</li>
        /// <li>3-4: New log version has been set, starting the writer will see that the new file exists and
        /// will be forgiving when trying to read the header of it, so that if it isn't complete a fresh
        /// header will be set.</li>
        /// </ol>
        ///
        /// Reading: what happens when rotation is between:
        /// <ol>
        /// <li>1-2: Reader bridge will see that there's a new version (when asking <seealso cref="LogVersionRepository"/>
        /// and try to open it. The log file doesn't exist yet though. The bridge can parry for this by catching
        /// <seealso cref="FileNotFoundException"/> and tell the reader that the stream has ended</li>
        /// <li>2-3: Same as (1-2)</li>
        /// <li>3-4: Here the new log file exists, but the header may not be fully written yet.
        /// the reader will fail when trying to read the header since it's reading it strictly and bridge
        /// catches that exception, treating it the same as if the file didn't exist.</li>
        /// </ol>
        /// </summary>
        /// <param name="currentLog"> current <seealso cref="LogVersionedStoreChannel channel"/> to flush and close. </param>
        /// <returns> the channel of the newly opened/created log file. </returns>
        /// <exception cref="IOException"> if an error regarding closing or opening log files occur. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private org.neo4j.kernel.impl.transaction.log.PhysicalLogVersionedStoreChannel rotate(org.neo4j.kernel.impl.transaction.log.LogVersionedStoreChannel currentLog) throws java.io.IOException
        private PhysicalLogVersionedStoreChannel Rotate(LogVersionedStoreChannel currentLog)
        {
            /*
             * The store is now flushed. If we fail now the recovery code will open the
             * current log file and replay everything. That's unnecessary but totally ok.
             */
            long newLogVersion = _logVersionRepository.incrementAndGetVersion();

            /*
             * Rotation can happen at any point, although not concurrently with an append,
             * although an append may have (most likely actually) left at least some bytes left
             * in the buffer for future flushing. Flushing that buffer now makes the last appended
             * transaction complete in the log we're rotating away. Awesome.
             */
            _writer.prepareForFlush().flush();

            /*
             * The log version is now in the store, flushed and persistent. If we crash
             * now, on recovery we'll attempt to open the version we're about to create
             * (but haven't yet), discover it's not there. That will lead to creating
             * the file, setting the header and continuing.
             * We using committing transaction id as a source of last transaction id here since
             * we can have transactions that are not yet published as committed but were already stored
             * into transaction log that was just rotated.
             */
            PhysicalLogVersionedStoreChannel newLog = _logFiles.createLogChannelForVersion(newLogVersion, OpenMode.READ_WRITE, _context.committingTransactionId);

            currentLog.close();
            return(newLog);
        }
示例#2
0
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public LogVersionedStoreChannel next(LogVersionedStoreChannel channel) throws java.io.IOException
        public override LogVersionedStoreChannel Next(LogVersionedStoreChannel channel)
        {
            PhysicalLogVersionedStoreChannel nextChannel;

            try
            {
                nextChannel = _logFiles.openForVersion(channel.Version + 1);
            }
            catch (Exception e) when(e is FileNotFoundException || e is IncompleteLogHeaderException)
            {
                // See PhysicalLogFile#rotate() for description as to why these exceptions are OK
                return(channel);
            }
            channel.close();
            return(nextChannel);
        }
示例#3
0
        /// <summary>
        /// Extracts txId from first commit entry, when starting reading at the given {@code position}.
        /// If no commit entry found in the version, the reader will continue into next version(s) up till
        /// {@code maxLogVersion} until finding one.
        /// </summary>
        /// <param name="initialPosition"> <seealso cref="LogPosition"/> to start scan from. </param>
        /// <param name="maxLogVersion"> max log version to scan. </param>
        /// <returns> value object that contains first transaction id of closes commit entry to {@code initialPosition},
        /// or <seealso cref="LogTailInformation.NO_TRANSACTION_ID"/> if not found. And failure flag that will be set to true if
        /// there was some exception during transaction log processing. </returns>
        /// <exception cref="IOException"> on channel close I/O error. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected ExtractedTransactionRecord extractFirstTxIdAfterPosition(org.neo4j.kernel.impl.transaction.log.LogPosition initialPosition, long maxLogVersion) throws java.io.IOException
        protected internal virtual ExtractedTransactionRecord ExtractFirstTxIdAfterPosition(LogPosition initialPosition, long maxLogVersion)
        {
            LogPosition currentPosition = initialPosition;

            while (currentPosition.LogVersion <= maxLogVersion)
            {
                LogVersionedStoreChannel storeChannel = TryOpenStoreChannel(currentPosition);
                if (storeChannel != null)
                {
                    try
                    {
                        storeChannel.Position(currentPosition.ByteOffset);
                        using (ReadAheadLogChannel logChannel = new ReadAheadLogChannel(storeChannel), LogEntryCursor cursor = new LogEntryCursor(_logEntryReader, logChannel))
                        {
                            while (cursor.Next())
                            {
                                LogEntry entry = cursor.Get();
                                if (entry is LogEntryCommit)
                                {
                                    return(new ExtractedTransactionRecord((( LogEntryCommit )entry).TxId));
                                }
                            }
                        }
                    }
                    catch (Exception t)
                    {
                        _monitor.corruptedLogFile(currentPosition.LogVersion, t);
                        return(new ExtractedTransactionRecord(true));
                    }
                    finally
                    {
                        storeChannel.close();
                    }
                }

                currentPosition = LogPosition.start(currentPosition.LogVersion + 1);
            }
            return(new ExtractedTransactionRecord());
        }