| 291 | } |
| 292 | |
| 293 | void TipCache::loadInventoryPages(thread_db* tdbb, GlobalTpcHeader* header) |
| 294 | { |
| 295 | // check the header page for the oldest and newest transaction numbers |
| 296 | |
| 297 | #ifdef SUPERSERVER_V2 |
| 298 | Database* dbb = tdbb->getDatabase(); |
| 299 | const TraNumber top = dbb->dbb_next_transaction; |
| 300 | const TraNumber hdr_oldest = dbb->dbb_oldest_transaction; |
| 301 | #else |
| 302 | WIN window(HEADER_PAGE_NUMBER); |
| 303 | const Ods::header_page* header_page = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header); |
| 304 | const TraNumber hdr_oldest_transaction = Ods::getOIT(header_page); |
| 305 | const TraNumber hdr_next_transaction = Ods::getNT(header_page); |
| 306 | const AttNumber hdr_attachment_id = Ods::getAttID(header_page); |
| 307 | CCH_RELEASE(tdbb, &window); |
| 308 | #endif |
| 309 | |
| 310 | header->oldest_transaction.store(hdr_oldest_transaction, std::memory_order_relaxed); |
| 311 | header->latest_attachment_id.store(hdr_attachment_id, std::memory_order_relaxed); |
| 312 | header->latest_transaction_id.store(hdr_next_transaction, std::memory_order_relaxed); |
| 313 | |
| 314 | // Check if TIP has any interesting transactions. |
| 315 | // At database creation time, it doesn't and the code below breaks |
| 316 | // if there isn't a single one transaction to care about. |
| 317 | if (hdr_oldest_transaction >= hdr_next_transaction) |
| 318 | return; |
| 319 | |
| 320 | // Round down the oldest to a multiple of four, which puts the |
| 321 | // transaction in temporary buffer on a byte boundary |
| 322 | TraNumber base = hdr_oldest_transaction & ~TRA_MASK; |
| 323 | |
| 324 | const FB_SIZE_T buffer_length = (hdr_next_transaction + 1 - base + TRA_MASK) / 4; |
| 325 | Array<UCHAR> transactions(buffer_length); |
| 326 | |
| 327 | UCHAR* buffer = transactions.begin(); |
| 328 | TRA_get_inventory(tdbb, buffer, base, hdr_next_transaction); |
| 329 | |
| 330 | static const CommitNumber init_state_mapping[4] = {CN_ACTIVE, CN_LIMBO, CN_DEAD, CN_PREHISTORIC}; |
| 331 | |
| 332 | TpcBlockNumber blockNumber = hdr_oldest_transaction / m_transactionsPerBlock; |
| 333 | ULONG transOffset = hdr_oldest_transaction % m_transactionsPerBlock; |
| 334 | |
| 335 | SyncLockGuard sync(&m_sync_status, SYNC_EXCLUSIVE, FB_FUNCTION); |
| 336 | TransactionStatusBlock* statusBlock = createTransactionStatusBlock(header->tpc_block_size, blockNumber); |
| 337 | |
| 338 | for (TraNumber t = hdr_oldest_transaction; ; ) |
| 339 | { |
| 340 | int state = TRA_state(buffer, base, t); |
| 341 | CommitNumber cn = init_state_mapping[state]; |
| 342 | |
| 343 | // Barrier is not needed as our thread is the only one here. |
| 344 | // At the same time, simple write to a volatile variable is not good |
| 345 | // as it is not deterministic. Some compilers generate barriers and some do not. |
| 346 | (statusBlock->data + transOffset)->store(cn, std::memory_order_relaxed); |
| 347 | |
| 348 | if (++t > hdr_next_transaction) |
| 349 | break; |
| 350 |
no test coverage detected