| 913 | |
| 914 | |
| 915 | SnapshotHandle TipCache::beginSnapshot(thread_db* tdbb, AttNumber attachmentId, CommitNumber& commitNumber) |
| 916 | { |
| 917 | // Can only be called on initialized TipCache |
| 918 | fb_assert(m_tpcHeader); |
| 919 | GlobalTpcHeader* header = m_tpcHeader->getHeader(); |
| 920 | |
| 921 | fb_assert(attachmentId); |
| 922 | |
| 923 | // Lock mutex |
| 924 | SharedMutexGuard guard(m_snapshots); |
| 925 | |
| 926 | // Remap snapshot list if it has been grown by someone else |
| 927 | remapSnapshots(false); |
| 928 | |
| 929 | SnapshotList* snapshots = m_snapshots->getHeader(); |
| 930 | |
| 931 | if (commitNumber != 0) |
| 932 | { |
| 933 | ULONG slotsUsed = snapshots->slots_used.load(std::memory_order_relaxed); |
| 934 | bool found = false; |
| 935 | |
| 936 | for (SnapshotHandle slotNumber = 0; slotNumber < slotsUsed; ++slotNumber) |
| 937 | { |
| 938 | if (snapshots->slots[slotNumber].attachment_id.load(std::memory_order_relaxed) != 0 && |
| 939 | snapshots->slots[slotNumber].snapshot.load(std::memory_order_relaxed) == commitNumber) |
| 940 | { |
| 941 | found = true; |
| 942 | break; |
| 943 | } |
| 944 | } |
| 945 | |
| 946 | if (!found) |
| 947 | ERR_post(Arg::Gds(isc_tra_snapshot_does_not_exist)); |
| 948 | } |
| 949 | |
| 950 | SnapshotHandle slotNumber = allocateSnapshotSlot(); |
| 951 | |
| 952 | // Note, that allocateSnapshotSlot might remap memory and thus invalidate pointers |
| 953 | snapshots = m_snapshots->getHeader(); |
| 954 | |
| 955 | // Store snapshot commit number and return handle |
| 956 | SnapshotData* slot = snapshots->slots + slotNumber; |
| 957 | |
| 958 | if (commitNumber == 0) |
| 959 | commitNumber = header->latest_commit_number.load(std::memory_order_acquire); |
| 960 | |
| 961 | slot->snapshot.store(commitNumber, std::memory_order_release); |
| 962 | |
| 963 | // Only assign attachment_id after we completed all other work |
| 964 | slot->attachment_id.store(attachmentId, std::memory_order_release); |
| 965 | |
| 966 | // And now move allocator watermark position after we used slot for sure |
| 967 | snapshots->min_free_slot = slotNumber + 1; |
| 968 | |
| 969 | return slotNumber; |
| 970 | } |
| 971 | |
| 972 | void TipCache::deallocateSnapshotSlot(SnapshotHandle slotNumber) |