Skip to content

Ch.5 ReadEvents() race condition issue #27

@ivasdtmbb

Description

@ivasdtmbb

Bug: ReadEvents fails due to shared lastSequence state

The ReadEvents method uses the struct field l.lastSequence, which is also modified by the Run method during event writing. This causes ReadEvents to fail with "transaction number out of sequence" if Run was called previously, even if the log file is valid.

The issue arises because ReadEvents should validate sequence order independently, starting from zero. Instead, it uses a shared counter that may already be non-zero.

Suggested fix:
Use a local lastSeq variable inside ReadEvents instead of l.lastSequence to track sequence order during reading.

This ensures that reading the log is independent of prior write operations and avoids false-positive errors.

// ReadEvents from File Transaction Log
func (l *FileTransactionLogger) ReadEvents() (<-chan Event, <-chan error) {
	scanner := bufio.NewScanner(l.file)
	outEvent := make(chan Event)
	outError := make(chan error)

	go func() {
		var e Event

		defer close(outEvent)
		defer close(outError)

		var lastSeq uint64 = 0

		for scanner.Scan() {
			line := scanner.Text()

			_, err := fmt.Sscanf(
				line,
				"%d\t%d\t%s\t%s",
				&e.Sequence, &e.EventType, &e.Key, &e.Value,
			)
			if err != nil {
				outError <- fmt.Errorf("transaction log parse error: %w", err)
				return
			}

			// Sanity check: Sequence number should be in increasing order
			if lastSeq >= e.Sequence {
				outError <- fmt.Errorf(
					"invalid sequence: expected sequence > %d, but got %d",
					l.lastSequence, e.Sequence,
				)
				return
			}
			lastSeq = e.Sequence

			outEvent <- e
		}

		if err := scanner.Err(); err != nil {
			outError <- fmt.Errorf("transaction log read failure: %w", err)
			return
		}
	}()
	return outEvent, outError
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions