void SG_dagfrag__equal(SG_context * pCtx, const SG_dagfrag * pFrag1, const SG_dagfrag * pFrag2, SG_bool * pbResult) { SG_rbtree_iterator * pIter1 = NULL; SG_rbtree_iterator * pIter2 = NULL; const char * szKey1; const char * szKey2; _my_data * pMyData1; _my_data * pMyData2; SG_bool bFound1, bFound2, bEqualDagnodes; SG_bool bFinalResult = SG_FALSE; SG_NULLARGCHECK_RETURN(pFrag1); SG_NULLARGCHECK_RETURN(pFrag2); SG_NULLARGCHECK_RETURN(pbResult); // we compare the RB-Cache because it has everything in it. // the work-queues are transient (used during __add_leaf()). // the generation-sorted-member-cache is only around when // needed and is a subset of the RB-Cache. // since the RB-Cache is ordered by HID, we don't need to do // any sorting. just walk both versions in parallel. SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx,&pIter1,pFrag1->m_pRB_Cache,&bFound1,&szKey1,(void **)&pMyData1) ); SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx,&pIter2,pFrag2->m_pRB_Cache,&bFound2,&szKey2,(void **)&pMyData2) ); while (1) { if (!bFound1 && !bFound2) goto Equal; if (!bFound1 || !bFound2) goto Different; if (strcmp(szKey1,szKey2) != 0) goto Different; if (pMyData1->m_state != pMyData2->m_state) goto Different; if (SG_DFS_END_FRINGE != pMyData1->m_state) { if (pMyData1->m_genDagnode != pMyData2->m_genDagnode) goto Different; SG_ERR_CHECK( SG_dagnode__equal(pCtx,pMyData1->m_pDagnode,pMyData2->m_pDagnode,&bEqualDagnodes) ); if (!bEqualDagnodes) goto Different; } SG_ERR_CHECK( SG_rbtree__iterator__next(pCtx,pIter1,&bFound1,&szKey1,(void **)&pMyData1) ); SG_ERR_CHECK( SG_rbtree__iterator__next(pCtx,pIter2,&bFound2,&szKey2,(void **)&pMyData2) ); } Equal: bFinalResult = SG_TRUE; Different: *pbResult = bFinalResult; fail: SG_RBTREE_ITERATOR_NULLFREE(pCtx, pIter1); SG_RBTREE_ITERATOR_NULLFREE(pCtx, pIter2); }
/** * Recursively compare dagnodes depth-first. */ static void _compare_dagnodes(SG_context* pCtx, SG_repo* pRepo1, SG_dagnode* pDagnode1, SG_repo* pRepo2, SG_dagnode* pDagnode2, SG_bool* pbIdentical) { SG_bool bDagnodesEqual = SG_FALSE; SG_uint32 iParentCount1, iParentCount2; const char** paParentIds1 = NULL; const char** paParentIds2 = NULL; SG_dagnode* pParentDagnode1 = NULL; SG_dagnode* pParentDagnode2 = NULL; SG_NULLARGCHECK_RETURN(pDagnode1); SG_NULLARGCHECK_RETURN(pDagnode2); SG_NULLARGCHECK_RETURN(pbIdentical); *pbIdentical = SG_TRUE; // Compare the dagnodes. If they're different, return false. SG_ERR_CHECK( SG_dagnode__equal(pCtx, pDagnode1, pDagnode2, &bDagnodesEqual) ); if (!bDagnodesEqual) { #if TRACE_SYNC SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDERR, "dagnodes not equal\n") ); #endif *pbIdentical = SG_FALSE; return; } // The dagnodes are identical. Look at their parents. SG_ERR_CHECK( SG_dagnode__get_parents(pCtx, pDagnode1, &iParentCount1, &paParentIds1) ); SG_ERR_CHECK( SG_dagnode__get_parents(pCtx, pDagnode2, &iParentCount2, &paParentIds2) ); if (iParentCount1 == iParentCount2) { // The dagnodes have the same number of parents. Compare the parents recursively. SG_uint32 i; for (i = 0; i < iParentCount1; i++) { SG_ERR_CHECK( SG_repo__fetch_dagnode(pCtx, pRepo1, paParentIds1[i], &pParentDagnode1) ); SG_ERR_CHECK( SG_repo__fetch_dagnode(pCtx, pRepo2, paParentIds2[i], &pParentDagnode2) ); SG_ERR_CHECK( _compare_dagnodes(pCtx, pRepo1, pParentDagnode1, pRepo2, pParentDagnode2, pbIdentical) ); SG_DAGNODE_NULLFREE(pCtx, pParentDagnode1); SG_DAGNODE_NULLFREE(pCtx, pParentDagnode2); if (!(*pbIdentical)) break; } } else { // The dagnodes have a different number of parents. *pbIdentical = SG_FALSE; } // fall through fail: SG_NULLFREE(pCtx, paParentIds1); SG_NULLFREE(pCtx, paParentIds2); SG_DAGNODE_NULLFREE(pCtx, pParentDagnode1); SG_DAGNODE_NULLFREE(pCtx, pParentDagnode2); }