Repository navigation
fix(TipCache): Committed transactions becoming invisible after TransactionStatusBlock is re-mapped - #9233
Open
TreeHunter9 wants to merge 6 commits into
Open
fix(TipCache): Committed transactions becoming invisible after TransactionStatusBlock is re-mapped#9233TreeHunter9 wants to merge 6 commits into
TransactionStatusBlock is re-mapped#9233TreeHunter9 wants to merge 6 commits into
Conversation
added 6 commits
October 20, 2026 10:51
- It is responsibility of the caller to memset new mapped region; - Bring this in line with Linux logic;
Member
|
Try this branch first: work/gh-9017-trace |
Member
No, file was truncated before that patch. Lines 2227-2237 in file before patch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of the problem
The TIP cache consists of fixed-size blocks called
TransactionStatusBlock (TSB)that contain a CN (Commit/Snapshot Number), where the transaction number serves as the index within that TSB. When a TSB fills up, the next TSB is created; that is, there can be several of them, and they are allocated as needed. A TSB is initialized upon the first connection to the database; it is then filled at runtime as transactions are executed. TSBs are also unloaded if no one is using a given block anymore. This is where the key problem lies: after a block is unloaded, it disappears, and if it is needed again, a new TSB will be allocated and initialized to zero, while the TIP will not be read from disk to load the current transaction statuses. In other words, when reading this TSB, we’ll get a CN equal to 0, where 0 represents the transaction statustra_active. This confusion leads to the following: a check begins to determine whether the transaction is actually active; the answer is negative; next, we read the TIP to obtain the current state, and it returnstra_committed. The two states receivedtra_active+tra_committedare interpreted as the transaction was committed after our transaction began, which means it should not be visible in our snapshot. As a result, these records become invisible to us, and we skip them, even though we should actually see them.Reproducable example
firebird.conf, setServerMode = ClassicandTipCacheBlockSize = 65536to fill the TSB more quickly (a single TSB can hold ~8k transactions);GlobalTpcHeader(which storeslatest_commit_number, used to generate the CN) remains active;The number 11240 was chosen to ensure we go exactly beyond the first TSB. Commit and disconnect;
create table tab1(a int);, commit, insert a recordinsert into tab1 values (1);, commit, and disconnect;select * from tab1, and see that nothing is returned;The main idea behind the fix
Basically, do not purge or memset to zero TSB when there is at least one connection to the database. Do it only when:
Description of changes that is not straight forward related to TipCache
statfor each file.SharedMemoryinitialization logic on Windows with Linux implementation. I discovered that on Windows there is initialization of zeros to newly mapped region, whereas on Linux the newly mapped region is left untouched, so this is creates some differences between platforms.I looked at Vlad's patch, which adds this initialization of zeros on Windows (by doing truncation of the file to 0 and then extend it back), and as I understand it, the main idea was not to perform memset, but to trigger an error to see whether any other instance of our server is holding the file (as I understand, because of IPC namespace/session differences, our
Eventwill not be visible to other instance). I have reimplement this check by doing exclusive access to file, so if there is any other instance that holds the file, we will get an error about it. I hope I'm not missing something about it, so I think @hvlad should look at this.And I think, the
SharedMemoryshould not memset mapped region to zero anyway, his responsibility is to simply perform ammap. The decision of whether to performmemsetor not should be left to the caller, not to the mapping mechanism.Affected versions
v6 and v5. I haven't tested this on other versions, but if the code is the same, then the issue applies to them as well.