Exemplo n.º 1
0
void SG_dbrecord__add_pair__int64(SG_context* pCtx, SG_dbrecord* prec, const char* putf8Name, SG_int64 intValue)
{
	SG_int_to_string_buffer buf;
	SG_int64_to_sz(intValue,buf);
	SG_ERR_CHECK_RETURN(  SG_dbrecord__add_pair(pCtx, prec, putf8Name, buf)  );
}
static void _tree__process_next_pending_item(SG_context * pCtx, _tree_t * pTree, SG_vhash * pMergeBaselines)
{
	SG_uint32 i;
	
	_node_t * pNode = NULL; // The node we are processing.
	SG_uint32 iNode = 0; // Index of pNode in the 'pending' list.
	
	SG_uint32 countVcParents = 0;
	const char ** paszVcParentHids = NULL;
	SG_uint32 iVcParent;
	
	// The first pending node that needs to be processed is always the one with
	// the highest revno. Find it in the list.
	for(i=1; i < pTree->pending.count; ++i)
	{
		if(pTree->pending.p[i]->revno > pTree->pending.p[iNode]->revno)
			iNode = i;
	}
	pNode = pTree->pending.p[iNode];
	
	// Load in the node's display children/vc parents.
	SG_ASSERT(pNode->displayChildren.count==0);
	SG_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pNode->pVcParents)  );
	SG_ERR_CHECK(  SG_dagnode__get_parents__ref(pCtx, pNode->pDagnode, &countVcParents, &paszVcParentHids)  );
	for(iVcParent=0; iVcParent<countVcParents; ++iVcParent)
	{
		// Each vc parent is a candidate display child.
		const char * pszHidCandidate = paszVcParentHids[iVcParent];
		_node_t * pNodeRef = NULL;
		
		// Scan through the list of 'pending' nodes to see if we have already
		// fetched this one...
		SG_uint32 iCandidate = pTree->pending.count;
		for(i=0; i < pTree->pending.count && iCandidate==pTree->pending.count; ++i)
		{
			if(strcmp(pTree->pending.p[i]->pszHidRef, pszHidCandidate)==0)
			{
				iCandidate = i;
				pNodeRef = pTree->pending.p[i];
			}
		}
		
		if(iCandidate == pTree->pending.count)
		{
			// Node was not found. Add it new.
			SG_ERR_CHECK(  _tree__add_new_node(pCtx, pTree, pNode, pszHidCandidate, &pNodeRef)  );
		}
		else if(iCandidate > iNode)
		{
			// Node was found further to the right in the tree. Steal it.
			SG_ERR_CHECK(  _tree__move_node(pCtx, pTree->pending.p[iCandidate], pNode)  );
			
			// Also, remove it from the pending list. (It gets re-added later.)
			_node_list__remove_at(&pTree->pending, iCandidate);
		}
		else
		{
			// Node was found further to the left. Do nothing.
		}

		SG_ERR_CHECK(  SG_vhash__add__int64(pCtx, pNode->pVcParents, pszHidCandidate, pNodeRef->revno)  );
	}
	
	// We have all this node's display children (still pending--they could get
	// stolen later). Now we need to sort them.
	
	if(pNode->displayChildren.count>1)
	{
		// First we pick one to go on the far left, if one stands out as most likely
		// to be the "old"/baseline node into which the others were "brought in".
		SG_uint32 iBaseline = pNode->displayChildren.count;
		
		// Allow the caller to have hand-picked the baseline node:
		if(pMergeBaselines!=NULL)
		{
			SG_int_to_string_buffer sz;

			SG_int64 baseline = 0;
			SG_ERR_CHECK(  SG_vhash__check__int64(pCtx, pMergeBaselines, SG_int64_to_sz(pNode->revno, sz), &baseline)  );
			if(baseline!=0)
			{
				for(i=0; i<pNode->displayChildren.count; ++i)
				{
					if(pNode->displayChildren.p[i]->revno==(SG_uint32)baseline)
					{
						iBaseline = i;
						break;
					}
				}
			}
		}
		
		if(iBaseline == pNode->displayChildren.count)
		{
			// No baseline node from the user. See if there's one unique node whose
			// user *doesn't* match.
			for(i=0; i<pNode->displayChildren.count; ++i)
			{
				SG_bool match = SG_FALSE;
				SG_ERR_CHECK(  _user_match_found(pCtx, pTree->pRepoRef, pNode->displayChildren.p[i], pNode, &match)  );
				if(!match)
				{
					if(iBaseline == pNode->displayChildren.count)
					{
						iBaseline = i;
					}
					else
					{
						// Whoops. "Nevermind."
						iBaseline = pNode->displayChildren.count;
						break;
					}
				}
			}
		}
		
		// Finally, sort
		_node_list__sort(&pNode->displayChildren, iBaseline);
	}
	
	// In the 'pending' list, replace this node with its children.
	if(pNode->displayChildren.count == 0)
		_node_list__remove_at(&pTree->pending, iNode);
	else
	{
		pTree->pending.p[iNode] = pNode->displayChildren.p[0];
		if(pNode->displayChildren.count > 1)
		{
			SG_ERR_CHECK(  _node_list__insert_at(pCtx,
				&pTree->pending,
				iNode+1,
				&pNode->displayChildren.p[1],
				pNode->displayChildren.count-1)  );
		}
	}
	
	// This node is no longer pending.
	pNode->isPending = SG_FALSE;

	return;
fail:
	;
}
void SG_mrg_cset_entry_conflict__append_change(SG_context * pCtx,
											   SG_mrg_cset_entry_conflict * pMrgCSetEntryConflict,
											   SG_mrg_cset_entry * pMrgCSetEntry_Leaf_k,
											   SG_mrg_cset_entry_neq neq)
{
	SG_NULLARGCHECK_RETURN(pMrgCSetEntryConflict);
	SG_NULLARGCHECK_RETURN(pMrgCSetEntry_Leaf_k);

	if (!pMrgCSetEntryConflict->pVec_MrgCSetEntry_Changes)
		SG_ERR_CHECK_RETURN(  SG_vector__alloc(pCtx,&pMrgCSetEntryConflict->pVec_MrgCSetEntry_Changes,2)  );

	SG_ERR_CHECK_RETURN(  SG_vector__append(pCtx,pMrgCSetEntryConflict->pVec_MrgCSetEntry_Changes,(void *)pMrgCSetEntry_Leaf_k,NULL)  );

	if (!pMrgCSetEntryConflict->pVec_MrgCSetEntryNeq_Changes)
		SG_ERR_CHECK_RETURN(  SG_vector_i64__alloc(pCtx,&pMrgCSetEntryConflict->pVec_MrgCSetEntryNeq_Changes,2)  );

	SG_ERR_CHECK_RETURN(  SG_vector_i64__append(pCtx,pMrgCSetEntryConflict->pVec_MrgCSetEntryNeq_Changes,(SG_int64)neq,NULL)  );

	//////////////////////////////////////////////////////////////////
	// add the value of the changed fields to the prbUnique_ rbtrees so that we can get a count of the unique new values.
	//
	//////////////////////////////////////////////////////////////////
	// the values for RENAME, MOVE, ATTRBITS, SYMLINKS, and SUBMODULES are collapsable.  that is, if we
	// have something like:
	//        A
	//       / \.
	//     L0   a0
	//         /  \.
	//        L1   L2
	//
	// and a rename in each Leaf, then we can either:
	// [a] prompt for them to choose L1 or L2's name and then
	//     prompt for them to choose L0 or the name from step 1.
	//
	// [b] prompt for them to choose L0, L1, or L2 in one question.
	//
	// unlike file-content-merging, the net-net is that we have 1 new value
	// that is one of the inputs (or maybe we let them pick a new onw), but
	// it is not a combination of them and so we don't need to display the
	// immediate ancestor in the prompt.
	//
	// so we carry-forward the unique values from the leaves for each of
	// these fields.  so the final merge-result may have more unique values
	// that it has direct parents.
	//////////////////////////////////////////////////////////////////

	if (neq & SG_MRG_CSET_ENTRY_NEQ__ATTRBITS)
	{
		SG_int_to_string_buffer buf;
		SG_int64_to_sz((SG_int64)pMrgCSetEntry_Leaf_k->attrBits, buf);

		if (!pMrgCSetEntryConflict->prbUnique_AttrBits)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_AttrBits)  );

		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,pMrgCSetEntryConflict->prbUnique_AttrBits,buf,pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_AttrBits)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_AttrBits,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_AttrBits)  );
	}

	if (neq & SG_MRG_CSET_ENTRY_NEQ__ENTRYNAME)
	{
		if (!pMrgCSetEntryConflict->prbUnique_Entryname)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_Entryname)  );

		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,
												 pMrgCSetEntryConflict->prbUnique_Entryname,
												 SG_string__sz(pMrgCSetEntry_Leaf_k->pStringEntryname),
												 pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Entryname)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_Entryname,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Entryname)  );
	}

	if (neq & SG_MRG_CSET_ENTRY_NEQ__GID_PARENT)
	{
		if (!pMrgCSetEntryConflict->prbUnique_GidParent)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_GidParent)  );

		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,pMrgCSetEntryConflict->prbUnique_GidParent,pMrgCSetEntry_Leaf_k->bufGid_Parent,pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_GidParent)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_GidParent,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_GidParent)  );
	}

	if (neq & SG_MRG_CSET_ENTRY_NEQ__SYMLINK_HID_BLOB)
	{
		if (!pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob)  );

		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob,pMrgCSetEntry_Leaf_k->bufHid_Blob,pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Symlink_HidBlob)  );
	}

	if (neq & SG_MRG_CSET_ENTRY_NEQ__SUBMODULE_HID_BLOB)
	{
		if (!pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob)  );

		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob,pMrgCSetEntry_Leaf_k->bufHid_Blob,pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_Submodule_HidBlob)  );
	}

	// 2010/09/13 Update: we now do the carry-forward on the set of
	//            unique HIDs for the various versions of the file
	//            content from each of the leaves.  This lets us
	//            completely flatten the sub-merges into one final
	//            result (with upto n values).
	//
	//            This means we won't be creating the auto-merge-plan
	//            at this point.
	//
	//            The problem with the auto-merge-plan as originally
	//            designed is that it was being driven based upon
	//            the overall topology of the DAG as a whole rather
	//            than the topology/history of the individual file.
	//            And by respecting the history of the individual
	//            file, I think we can get closer ancestors and better
	//            per-file merging and perhaps fewer criss-crosses
	//            and/or we push all of these issues to RESOLVE.

	if (neq & SG_MRG_CSET_ENTRY_NEQ__FILE_HID_BLOB)
	{
		if (!pMrgCSetEntryConflict->prbUnique_File_HidBlob)
			SG_ERR_CHECK_RETURN(  SG_RBTREE__ALLOC(pCtx,&pMrgCSetEntryConflict->prbUnique_File_HidBlob)  );

		SG_ASSERT(  (pMrgCSetEntry_Leaf_k->bufHid_Blob[0])  );

		// TODO 2010/09/13 the code that sets __FILE_HID_BLOB probably cannot tell
		// TODO            whether this branch did not change the file content
		// TODO            relative to the LCA or whether it did change it back to
		// TODO            the original value (an UNDO of the edits).  I would argue
		// TODO            that we should not list the former as a change, but that
		// TODO            we SHOULD list the latter.  The fix doesn't belong here,
		// TODO            but this is just where I was typing when I thought of it.
		
		SG_ERR_CHECK_RETURN(  _update_1_rbUnique(pCtx,pMrgCSetEntryConflict->prbUnique_File_HidBlob,pMrgCSetEntry_Leaf_k->bufHid_Blob,pMrgCSetEntry_Leaf_k)  );

		if (pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict && pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_File_HidBlob)
			SG_ERR_CHECK_RETURN(  _carry_forward_unique_values(pCtx,
															   pMrgCSetEntryConflict->prbUnique_File_HidBlob,
															   pMrgCSetEntry_Leaf_k->pMrgCSetEntryConflict->prbUnique_File_HidBlob)  );
	}
}