Mark next difference page as used by some database page
| 740 | |
| 741 | // Mark next difference page as used by some database page |
| 742 | ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page) |
| 743 | { |
| 744 | LocalAllocWriteGuard localAllocGuard(this); |
| 745 | |
| 746 | // This page may be allocated while we wait for a local lock above |
| 747 | if (ULONG diff_page = findPageIndex(tdbb, db_page)) { |
| 748 | return diff_page; |
| 749 | } |
| 750 | |
| 751 | GlobalAllocWriteGuard globalAllocGuard(tdbb, this); |
| 752 | |
| 753 | // This page may be allocated by other process |
| 754 | if (ULONG diff_page = findPageIndex(tdbb, db_page)) { |
| 755 | return diff_page; |
| 756 | } |
| 757 | |
| 758 | NBAK_TRACE(("allocate_difference_page")); |
| 759 | fb_assert(last_allocated_page % (database->dbb_page_size / sizeof(ULONG)) == alloc_buffer[0]); |
| 760 | |
| 761 | FbStatusVector* status_vector = tdbb->tdbb_status_vector; |
| 762 | // Grow file first. This is done in such order to keep difference |
| 763 | // file consistent in case of write error. We should always be able |
| 764 | // to read next alloc page when previous one is full. |
| 765 | BufferDesc temp_bdb(database->dbb_bcb); |
| 766 | temp_bdb.bdb_page = last_allocated_page + 1; |
| 767 | temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer); |
| 768 | if (!PIO_write(tdbb, diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector)) |
| 769 | return 0; |
| 770 | |
| 771 | const bool alloc_page_full = alloc_buffer[0] == database->dbb_page_size / sizeof(ULONG) - 2; |
| 772 | if (alloc_page_full) |
| 773 | { |
| 774 | // Pointer page is full. Its time to create new one. |
| 775 | temp_bdb.bdb_page = last_allocated_page + 2; |
| 776 | temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer); |
| 777 | if (!PIO_write(tdbb, diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector)) |
| 778 | return 0; |
| 779 | } |
| 780 | |
| 781 | // Write new item to the allocation table |
| 782 | temp_bdb.bdb_page = last_allocated_page & ~(database->dbb_page_size / sizeof(ULONG) - 1); |
| 783 | temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(alloc_buffer); |
| 784 | alloc_buffer[++alloc_buffer[0]] = db_page; |
| 785 | if (!PIO_write(tdbb, diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector)) |
| 786 | return 0; |
| 787 | |
| 788 | last_allocated_page++; |
| 789 | |
| 790 | // Register new page in the alloc table |
| 791 | try |
| 792 | { |
| 793 | alloc_table->add(AllocItem(db_page, last_allocated_page)); |
| 794 | } |
| 795 | catch (const Firebird::Exception& ex) |
| 796 | { |
| 797 | // Handle out of memory error |
| 798 | delete alloc_table; |
| 799 | alloc_table = NULL; |
no test coverage detected