CFDictionaryRef WebBackForwardList::createCFDictionaryRepresentation(WebPageProxy::WebPageProxySessionStateFilterCallback filter, void* context) const { ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size()); RetainPtr<CFMutableArrayRef> entries(AdoptCF, CFArrayCreateMutable(0, m_entries.size(), &kCFTypeArrayCallBacks)); // We may need to update the current index to account for entries that are filtered by the callback. int currentIndex = m_current; for (size_t i = 0; i < m_entries.size(); ++i) { RefPtr<WebURL> webURL = WebURL::create(m_entries[i]->url()); if (filter && !filter(toAPI(m_page), WKPageGetSessionHistoryURLValueType(), toURLRef(m_entries[i]->originalURL().impl()), context)) { if (i <= static_cast<size_t>(m_current)) currentIndex--; continue; } RetainPtr<CFStringRef> url(AdoptCF, m_entries[i]->url().createCFString()); RetainPtr<CFStringRef> title(AdoptCF, m_entries[i]->title().createCFString()); RetainPtr<CFStringRef> originalURL(AdoptCF, m_entries[i]->originalURL().createCFString()); RetainPtr<CFDataRef> entryData(AdoptCF, CFDataCreate(kCFAllocatorDefault, m_entries[i]->backForwardData().data(), m_entries[i]->backForwardData().size())); const void* keys[4] = { SessionHistoryEntryURLKey(), SessionHistoryEntryTitleKey(), SessionHistoryEntryOriginalURLKey(), SessionHistoryEntryDataKey() }; const void* values[4] = { url.get(), title.get(), originalURL.get(), entryData.get() }; RetainPtr<CFDictionaryRef> entryDictionary(AdoptCF, CFDictionaryCreate(0, keys, values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFArrayAppendValue(entries.get(), entryDictionary.get()); } ASSERT(currentIndex < CFArrayGetCount(entries.get())); RetainPtr<CFNumberRef> currentIndexNumber(AdoptCF, CFNumberCreate(0, kCFNumberIntType, ¤tIndex)); const void* keys[2] = { SessionHistoryCurrentIndexKey(), SessionHistoryEntriesKey() }; const void* values[2] = { currentIndexNumber.get(), entries.get() }; return CFDictionaryCreate(0, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); }
void ColumnMapScanProcessor::processMainPage(const ColumnMapMainPage* page, uint64_t startIdx, uint64_t endIdx) { mKeyData.resize(page->count, 0u); mValidFromData.resize(page->count, 0u); mValidToData.resize(page->count, 0u); auto resultSize = mNumConjuncts * page->count; if (mResult.size() < resultSize) { mResult.resize(resultSize, 0u); } auto entries = page->entryData(); auto sizeData = page->sizeData(); auto i = startIdx; while (i < endIdx) { auto key = entries[i].key; auto newest = entries[i].newest.load(); auto validTo = std::numeric_limits<uint64_t>::max(); if (newest != 0u) { if ((newest & crossbow::to_underlying(NewestPointerTag::INVALID)) != 0x0u) { // Skip to element with next key auto j = i; for (++i; i < endIdx && entries[i].key == key; ++i); if (startIdx == j) { startIdx = i; } continue; } if (auto relocated = reinterpret_cast<const ColumnMapMainEntry*>(newestMainRecord(newest))) { if (i > startIdx) { evaluateMainQueries(page, startIdx, i); } auto relocatedPage = mContext.pageFromEntry(relocated); auto relocatedStartIdx = ColumnMapContext::pageIndex(relocatedPage, relocated); auto relocatedEndIdx = relocatedStartIdx; while (true) { for (++i; i < endIdx && entries[i].key == key; ++i); if (i >= endIdx) { break; } key = entries[i].key; newest = entries[i].newest.load(); relocated = reinterpret_cast<const ColumnMapMainEntry*>(newestMainRecord(newest)); if (relocated) { if (mContext.pageFromEntry(relocated) != relocatedPage) { break; } relocatedEndIdx = ColumnMapContext::pageIndex(relocatedPage, relocated); } else if ((newest & crossbow::to_underlying(NewestPointerTag::INVALID)) != 0x0u) { continue; } else { break; } } auto relocatedEntries = relocatedPage->entryData(); key = relocatedEntries[relocatedEndIdx].key; for (++relocatedEndIdx; relocatedEndIdx < relocatedPage->count && relocatedEntries[relocatedEndIdx].key == key; ++relocatedEndIdx); processMainPage(relocatedPage, relocatedStartIdx, relocatedEndIdx); if (i >= endIdx) { return; } mKeyData.resize(page->count, 0u); mValidFromData.resize(page->count, 0u); mValidToData.resize(page->count, 0u); startIdx = i; continue; } auto lowestVersion = processUpdateRecord(reinterpret_cast<const UpdateLogEntry*>(newest), entries[i].version, validTo); // Skip elements with version above lowest version and set the valid-to version to 0 to exclude them from // the query processing auto j = i; for (; i < endIdx && entries[i].key == key && entries[i].version >= lowestVersion; ++i); if (startIdx == j) { startIdx = i; } } // Set valid-to version for every element of the same key to the valid-from version of the previous // If the element marks a deletion set the valid-to version to 0 to exclude them from the query processing. for (; i < endIdx && entries[i].key == key; ++i) { if (sizeData[i] != 0) { mKeyData[i] = key; mValidFromData[i] = entries[i].version; mValidToData[i] = validTo; } validTo = entries[i].version; } } if (startIdx < endIdx) { evaluateMainQueries(page, startIdx, endIdx); } }
void ColumnMapScanProcessor::process() { for (auto i = pageIdx; i < pageEndIdx; ++i) { processMainPage(pages[i], 0, pages[i]->count); } auto insIter = logIter; while (insIter != logEnd) { if (!insIter->sealed()) { ++insIter; continue; } auto ptr = reinterpret_cast<const InsertLogEntry*>(insIter->data()); ConstInsertRecord record(ptr); if (!record.valid()) { ++insIter; continue; } if (auto relocated = reinterpret_cast<const ColumnMapMainEntry*>(newestMainRecord(record.newest()))) { auto relocatedPage = mContext.pageFromEntry(relocated); auto relocatedStartIdx = ColumnMapContext::pageIndex(relocatedPage, relocated); auto relocatedEndIdx = relocatedStartIdx; for (++insIter; insIter != logEnd; ++insIter) { if (!insIter->sealed()) { continue; } ptr = reinterpret_cast<const InsertLogEntry*>(insIter->data()); record = ConstInsertRecord(ptr); relocated = reinterpret_cast<const ColumnMapMainEntry*>(newestMainRecord(record.newest())); if (relocated) { if (mContext.pageFromEntry(relocated) != relocatedPage) { break; } relocatedEndIdx = ColumnMapContext::pageIndex(relocatedPage, relocated); } else if (!record.valid()) { continue; } else { break; } } auto relocatedEntries = relocatedPage->entryData(); auto key = relocatedEntries[relocatedEndIdx].key; for (++relocatedEndIdx; relocatedEndIdx < relocatedPage->count && relocatedEntries[relocatedEndIdx].key == key; ++relocatedEndIdx); processMainPage(relocatedPage, relocatedStartIdx, relocatedEndIdx); continue; } auto validTo = std::numeric_limits<uint64_t>::max(); if (record.newest() != 0u) { auto lowestVersion = processUpdateRecord(reinterpret_cast<const UpdateLogEntry*>(record.newest()), record.baseVersion(), validTo); if (ptr->version >= lowestVersion) { ++insIter; continue; } } auto entry = LogEntry::entryFromData(reinterpret_cast<const char*>(ptr)); processRowRecord(ptr->key, ptr->version, validTo, ptr->data(), entry->size() - sizeof(InsertLogEntry)); ++insIter; } }