HRESULT ProductSyncValues( __in CFGDB_STRUCT *pcdb1, __in CFGDB_STRUCT *pcdb2, __in BOOL fAllowLocalToReceiveData, __in STRINGDICT_HANDLE shDictValuesSeen, __out CONFLICT_PRODUCT **ppcpProduct ) { HRESULT hr = S_OK; LPWSTR sczName = NULL; DWORD dwInserting = 0; SCE_QUERY_HANDLE sqhHandle = NULL; SCE_QUERY_RESULTS_HANDLE sqrhResults = NULL; SCE_ROW_HANDLE sceRow = NULL; DWORD dwFoundIndex = 0; DWORD dwSubsumeIndex = 0; BOOL fSame = FALSE; BOOL fFirstIsLocal = (NULL == pcdb1->pcdbLocal); CFG_ENUMERATION * valueHistory1 = NULL; DWORD dwCfgCount1 = 0; CFG_ENUMERATION * valueHistory2 = NULL; DWORD dwCfgCount2 = 0; hr = SceBeginQuery(pcdb1->psceDb, VALUE_INDEX_TABLE, 0, &sqhHandle); ExitOnFailure(hr, "Failed to begin query into value table"); hr = SceSetQueryColumnDword(sqhHandle, pcdb1->dwAppID); ExitOnFailure(hr, "Failed to set query column dword to: %u", pcdb1->dwAppID); hr = SceRunQueryRange(&sqhHandle, &sqrhResults); if (E_NOTFOUND == hr) { ExitFunction1(hr = S_OK); } ExitOnFailure(hr, "Failed to enumerate values for product %u", pcdb1->dwAppID); hr = SceGetNextResultRow(sqrhResults, &sceRow); while (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get next row from query into value table"); CfgReleaseEnumeration(valueHistory1); valueHistory1 = NULL; CfgReleaseEnumeration(valueHistory2); valueHistory2 = NULL; hr = SceGetColumnString(sceRow, VALUE_COMMON_NAME, &sczName); ExitOnFailure(hr, "Failed to get value name"); if (NULL != shDictValuesSeen) { hr = DictKeyExists(shDictValuesSeen, sczName); if (E_NOTFOUND == hr) { hr = DictAddKey(shDictValuesSeen, sczName); ExitOnFailure(hr, "Failed to add to dictionary value: %ls", sczName); } else { ExitOnFailure(hr, "Failed to check if key exists: %ls", sczName); // This value was already synced; skip it! goto Skip; } } // Exclude legacy detect cache values, they should never be synced off the machine // TODO: when we support per-machine settings, migrate this to use that feature if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczName, lstrlenW(wzLegacyDetectCacheValuePrefix), wzLegacyDetectCacheValuePrefix, lstrlenW(wzLegacyDetectCacheValuePrefix))) { goto Skip; } // First check if the values are identical. Even if they were set by different folks at different times, // same value means nothing to sync. hr = ValueMatch(sczName, pcdb1, pcdb2, sceRow, &fSame); ExitOnFailure(hr, "Failed to check if values are identical"); if (fSame) { goto Skip; } // Get history of the value in db2 hr = EnumPastValues(pcdb2, sczName, &valueHistory2, &dwCfgCount2); if (E_NOTFOUND == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to enumerate previous values in db2"); // Get history of the value in db1 hr = EnumPastValues(pcdb1, sczName, &valueHistory1, &dwCfgCount1); ExitOnFailure(hr, "Found value in db1, but failed to enumerate previous values in db1 while searching for conflicts"); if (0 == dwCfgCount2) { if (fFirstIsLocal || fAllowLocalToReceiveData) { hr = ValueTransferFromHistory(pcdb2, valueHistory1, 0, pcdb1); ExitOnFailure(hr, "Failed to transfer history (due to value not present) from db 2 to db 1 for value %ls", sczName); } goto Skip; } // Don't write anything to db2 if it's local and we're told not to if (fFirstIsLocal || fAllowLocalToReceiveData) { // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too. // This reduces unnecessary conflicts in rare corner case scenarios. dwSubsumeIndex = dwCfgCount2; do { --dwSubsumeIndex; // Check if the last history entry for database 2 exists in the database 1 - if it does, database 2's changes are subsumed hr = EnumFindValueInHistory(valueHistory1, dwCfgCount1, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex); if (S_OK == hr) { // Database 2 is subsumed - pipe over all the newest history entries hr = ValueTransferFromHistory(pcdb2, valueHistory1, dwFoundIndex + 1, pcdb1); ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 1 to db 2 for value %ls", sczName); goto Skip; } else if (E_NOTFOUND == hr) { hr = S_OK; } else { ExitOnFailure(hr, "Failed to check if db2's value history is subsumed by db1's value history"); } if (0 < dwSubsumeIndex) { hr = ValueCompare(valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame); ExitOnFailure(hr, "Failed to check if value and previous value in database 2 are equivalent"); } } while (0 < dwSubsumeIndex && fSame); } // Don't write anything to db1 if it's local and we're told not to if (!fFirstIsLocal || fAllowLocalToReceiveData) { // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too. // This reduces unnecessary conflicts in rare corner case scenarios. dwSubsumeIndex = dwCfgCount1; do { --dwSubsumeIndex; hr = EnumFindValueInHistory(valueHistory2, dwCfgCount2, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex); if (S_OK == hr) { // Database 1 is subsumed - pipe over all the newest history entries hr = ValueTransferFromHistory(pcdb1, valueHistory2, dwFoundIndex + 1, pcdb2); ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 2 to db 1 for value %ls", sczName); goto Skip; } else if (E_NOTFOUND == hr) { hr = S_OK; } else { ExitOnFailure(hr, "Failed to check if db1's value history is subsumed by db2's value history"); } if (0 < dwSubsumeIndex) { hr = ValueCompare(valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame); ExitOnFailure(hr, "Failed to check if value and previous value in database 1 are equivalent"); } } while (0 < dwSubsumeIndex && fSame); } // OK, we have a conflict. Report it. if (NULL == *ppcpProduct) { *ppcpProduct = static_cast<CONFLICT_PRODUCT *>(MemAlloc(sizeof(CONFLICT_PRODUCT), TRUE)); ExitOnNull(*ppcpProduct, hr, E_OUTOFMEMORY, "Failed to allocate product conflict struct"); (*ppcpProduct)->cValues = 1; } else { ++(*ppcpProduct)->cValues; } hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumLocal), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10); ExitOnFailure(hr, "Failed to ensure product local value conflict array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountLocal), (*ppcpProduct)->cValues, sizeof(DWORD), 10); ExitOnFailure(hr, "Failed to ensure product local value conflict count array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumRemote), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10); ExitOnFailure(hr, "Failed to ensure product remote value conflict array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountRemote), (*ppcpProduct)->cValues, sizeof(DWORD), 10); ExitOnFailure(hr, "Failed to ensure product remote value conflict count array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgrcValueChoices), (*ppcpProduct)->cValues, sizeof(RESOLUTION_CHOICE), 10); ExitOnFailure(hr, "Failed to ensure product value resolution choice array size"); dwInserting = (*ppcpProduct)->cValues - 1; // Neither is subsumed by the other, so we have conflicts - report them if (fFirstIsLocal) { hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1, reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2, &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting], &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]); } else { hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2, reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1, &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting], &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]); } ExitOnFailure(hr, "Failed to get conflict list"); Skip: ReleaseNullSceRow(sceRow); hr = SceGetNextResultRow(sqrhResults, &sceRow); } hr = S_OK; LExit: ReleaseSceQuery(sqhHandle); ReleaseSceQueryResults(sqrhResults); ReleaseSceRow(sceRow); CfgReleaseEnumeration(valueHistory1); CfgReleaseEnumeration(valueHistory2); ReleaseStr(sczName); return hr; }
ordered_adaptor_iterator(void): container(NULL), current_index((std::numeric_limits<size_t>::max)()), unvisited_nodes(compare_by_heap_value(NULL, ValueCompare())) {}
ordered_adaptor_iterator(const ContainerType * container, ValueCompare const & cmp): container(container), current_index(container->size()), unvisited_nodes(compare_by_heap_value(container, ValueCompare())) {}
tree_iterator(void): adaptor_type(0), unvisited_nodes(ValueCompare()) {}