| 291 | } |
| 292 | |
| 293 | bool TRA_cleanup(thread_db* tdbb) |
| 294 | { |
| 295 | /************************************** |
| 296 | * |
| 297 | * T R A _ c l e a n u p |
| 298 | * |
| 299 | ************************************** |
| 300 | * |
| 301 | * Functional description |
| 302 | * TRA_cleanup is called at startup while an exclusive lock is |
| 303 | * held on the database. Because we haven't started a transaction, |
| 304 | * and we have an exclusive lock on the db, any transactions marked |
| 305 | * as active on the transaction inventory pages are indeed dead. |
| 306 | * Mark them so. |
| 307 | * |
| 308 | **************************************/ |
| 309 | SET_TDBB(tdbb); |
| 310 | Database* dbb = tdbb->getDatabase(); |
| 311 | CHECK_DBB(dbb); |
| 312 | |
| 313 | // Return without cleaning up the TIP's for a ReadOnly database |
| 314 | if (dbb->readOnly()) |
| 315 | return false; |
| 316 | |
| 317 | // First, make damn sure there are no outstanding transactions |
| 318 | |
| 319 | for (Jrd::Attachment* attachment = dbb->dbb_attachments; attachment; |
| 320 | attachment = attachment->att_next) |
| 321 | { |
| 322 | if (attachment->att_transactions) |
| 323 | return false; |
| 324 | } |
| 325 | |
| 326 | const ULONG trans_per_tip = dbb->dbb_page_manager.transPerTIP; |
| 327 | |
| 328 | // Read header page and allocate transaction number. Since |
| 329 | // the transaction inventory page was initialized to zero, it |
| 330 | // transaction is automatically marked active. |
| 331 | |
| 332 | WIN window(HEADER_PAGE_NUMBER); |
| 333 | const header_page* header = (header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header); |
| 334 | const TraNumber ceiling = Ods::getNT(header); |
| 335 | const TraNumber active = Ods::getOAT(header); |
| 336 | CCH_RELEASE(tdbb, &window); |
| 337 | |
| 338 | if (ceiling == 0) |
| 339 | return false; |
| 340 | |
| 341 | // Zip thru transactions from the "oldest active" to the next looking for |
| 342 | // active transactions. When one is found, declare it dead. |
| 343 | |
| 344 | const ULONG last = ceiling / trans_per_tip; |
| 345 | ULONG number = active % trans_per_tip; |
| 346 | TraNumber limbo = 0; |
| 347 | bool found = false; |
| 348 | |
| 349 | for (ULONG sequence = active / trans_per_tip; sequence <= last; sequence++, number = 0) |
| 350 | { |
no test coverage detected