| 1027 | } |
| 1028 | |
| 1029 | void TipCache::updateActiveSnapshots(thread_db* tdbb, ActiveSnapshots* activeSnapshots) |
| 1030 | { |
| 1031 | // Can only be called on initialized TipCache |
| 1032 | fb_assert(m_tpcHeader); |
| 1033 | GlobalTpcHeader* header = m_tpcHeader->getHeader(); |
| 1034 | |
| 1035 | fb_assert(activeSnapshots); |
| 1036 | |
| 1037 | // This function is quite tricky as it reads snapshots list without locks (using atomics) |
| 1038 | |
| 1039 | SnapshotList* snapshots = m_snapshots->getHeader(); |
| 1040 | |
| 1041 | if (activeSnapshots->m_lastCommit == CN_ACTIVE) |
| 1042 | { |
| 1043 | // Slow path. Initialization. |
| 1044 | |
| 1045 | activeSnapshots->m_lastCommit = header->latest_commit_number.load(std::memory_order_acquire); |
| 1046 | activeSnapshots->m_releaseCount = header->snapshot_release_count.load(std::memory_order_relaxed); |
| 1047 | |
| 1048 | // If new slots are allocated past this value - we don't care as we preserved |
| 1049 | // lastCommit and new snapshots will have numbers >= lastCommit and we don't |
| 1050 | // GC them anyways |
| 1051 | ULONG slots_used_org = snapshots->slots_used.load(std::memory_order_acquire); |
| 1052 | |
| 1053 | // Remap snapshot list if it has been grown by someone else |
| 1054 | remapSnapshots(true); |
| 1055 | |
| 1056 | snapshots = m_snapshots->getHeader(); |
| 1057 | |
| 1058 | GenericMap<Pair<NonPooled<AttNumber, bool> > > att_states; |
| 1059 | |
| 1060 | // We modify snapshots list only while holding a mutex |
| 1061 | SharedMutexGuard guard(m_snapshots, false); |
| 1062 | |
| 1063 | activeSnapshots->m_snapshots.clear(); |
| 1064 | for (ULONG slotNumber = 0; slotNumber < slots_used_org; slotNumber++) |
| 1065 | { |
| 1066 | SnapshotData* slot = snapshots->slots + slotNumber; |
| 1067 | AttNumber slot_attachment_id = slot->attachment_id.load(std::memory_order_acquire); |
| 1068 | if (slot_attachment_id) |
| 1069 | { |
| 1070 | bool isAttachmentDead; |
| 1071 | if (!att_states.get(slot_attachment_id, isAttachmentDead)) |
| 1072 | { |
| 1073 | ThreadStatusGuard temp_status(tdbb); |
| 1074 | Lock temp_lock(tdbb, sizeof(AttNumber), LCK_attachment); |
| 1075 | temp_lock.setKey(slot_attachment_id); |
| 1076 | if ((isAttachmentDead = LCK_lock(tdbb, &temp_lock, LCK_EX, LCK_NO_WAIT))) |
| 1077 | LCK_release(tdbb, &temp_lock); |
| 1078 | att_states.put(slot_attachment_id, isAttachmentDead); |
| 1079 | } |
| 1080 | |
| 1081 | if (isAttachmentDead) |
| 1082 | { |
| 1083 | if (!guard.isLocked()) |
| 1084 | { |
| 1085 | guard.lock(); |
| 1086 | |