/**
 * Is this object a candidate for short-circuit evaluation?  That is, can we
 * avoid diving into this pair of folders and recursively comparing everything
 * within.
 *
 * We must have a pair of unscanned folders with equal content HIDs.  If one has
 * already been scanned, we must scan the other so that the children don't look
 * like peerless objects.  (We either scan neither or both.)
 *
 * If we have pendingtree data, we don't know how much of the tree it populated.
 * If the dsFlags in the pendingtree version indicate a change *on* the folder
 * (such as a rename/move), we can still allow the short-circuit; only if it
 * indicates a change in the stuff *within* the folder do we force it to continue.
 * This is another instance of the accidental peerless problem.
 */
void sg_vv2__status__can_short_circuit_from_work_queue(SG_context * pCtx,
													   const sg_vv2status_od * pOD,
													   SG_bool * pbCanShortCircuit)
{
	SG_bool bEqual;
	const char * pszHid_orig;
	const char * pszHid_dest;

	SG_UNUSED( pCtx );
	if (!pOD->apInst[SG_VV2__OD_NDX_ORIG])
		goto no;
	if (!pOD->apInst[SG_VV2__OD_NDX_DEST])
		goto no;

	if (pOD->apInst[SG_VV2__OD_NDX_ORIG]->typeInst != SG_VV2__OD_TYPE_UNSCANNED_FOLDER)
		goto no;
	if (pOD->apInst[SG_VV2__OD_NDX_DEST]->typeInst != SG_VV2__OD_TYPE_UNSCANNED_FOLDER)
		goto no;

	SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pOD->apInst[SG_VV2__OD_NDX_ORIG]->pTNE, &pszHid_orig)  );
	SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pOD->apInst[SG_VV2__OD_NDX_DEST]->pTNE, &pszHid_dest)  );
	
	bEqual = (strcmp(pszHid_orig, pszHid_dest) == 0);
	if (!bEqual)
		goto no;

	*pbCanShortCircuit = SG_TRUE;
	return;

no:
	*pbCanShortCircuit = SG_FALSE;

fail:
	return;
}
示例#2
0
static void _sg_workingdir__get_entry(SG_context* pCtx,
									  SG_repo* pRepo,
									  const SG_pathname* pPathSub,
									  const char * pszGid,
									  const SG_treenode_entry* pEntry,
									  SG_vhash * pvhTimestamps)
{
    SG_treenode_entry_type type;
    const char* pszidHidContent = NULL;
    const char* pszidHidXattrs = NULL;
    SG_int64 iAttributeBits = 0;

    SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pEntry, &type)  );
    SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pEntry, &pszidHidContent)  );
    SG_ERR_CHECK(  SG_treenode_entry__get_hid_xattrs(pCtx, pEntry, &pszidHidXattrs)  );
    SG_ERR_CHECK(  SG_treenode_entry__get_attribute_bits(pCtx, pEntry, &iAttributeBits)  );

	SG_ERR_CHECK(  _sg_workingdir__get_entry2(pCtx, pRepo, pPathSub,
											  pszGid,
											  type, pszidHidContent, pszidHidXattrs, iAttributeBits,
											  pvhTimestamps)  );

fail:
    return;
}
/**
 * INSERT or UPDATE this TreeNodeEntry and if a directory,
 * dive into it and INSERT/UPDATE the contents of the directory.
 */
void sg_wc_db__tne__insert_recursive(SG_context * pCtx,
									 sg_wc_db * pDb,
									 const sg_wc_db__cset_row * pCSetRow,
									 sqlite3_stmt * pStmt,
									 SG_uint64 uiAliasGidParent,
									 SG_uint64 uiAliasGid,
									 const SG_treenode_entry * pTreenodeEntry)
{
	SG_treenode * pTreenode = NULL;
	SG_uint32 nrEntries, k;
	SG_treenode_entry_type tneType;

	SG_ERR_CHECK(  sg_wc_db__tne__bind_insert_and_step(pCtx, pStmt,
													   uiAliasGid,
													   uiAliasGidParent,
													   pTreenodeEntry)  );
	
	SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pTreenodeEntry, &tneType)  );
	if (tneType == SG_TREENODEENTRY_TYPE_DIRECTORY)
	{
		const char * pszHid = NULL;				// we do not own this

		// dive into the contents of the directory and load them.

		SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pTreenodeEntry, &pszHid)  );
		SG_ERR_CHECK(  SG_treenode__load_from_repo(pCtx, pDb->pRepo, pszHid, &pTreenode)  );
	
		SG_ERR_CHECK(  SG_treenode__count(pCtx, pTreenode, &nrEntries)  );
		for (k=0; k<nrEntries; k++)
		{
			const char * pszGid_k = NULL;							// we do not own this
			const SG_treenode_entry * pTreenodeEntry_k = NULL;		// we do not own this
			SG_uint64 uiAliasGid_k = 0;

			SG_ERR_CHECK(  SG_treenode__get_nth_treenode_entry__ref(pCtx,
																	pTreenode,
																	k,
																	&pszGid_k,
																	&pTreenodeEntry_k)  );

			SG_ERR_CHECK(  sg_wc_db__gid__insert(pCtx, pDb, pszGid_k)  );
			SG_ERR_CHECK(  sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, pszGid_k, &uiAliasGid_k)  );

			SG_ERR_CHECK(  sg_wc_db__tne__insert_recursive(pCtx, pDb, pCSetRow, pStmt,
														   uiAliasGid, uiAliasGid_k,
														   pTreenodeEntry_k)  );
		}
	}
	
fail:
	SG_TREENODE_NULLFREE(pCtx, pTreenode);
}
示例#4
0
void sg_pack__get_dir(SG_context* pCtx, SG_repo* pRepo, SG_int32 gen, const char* pszidHidTreeNode, SG_rbtree* prb_blobs, SG_rbtree* prb_new)
{
	SG_uint32 count;
	SG_uint32 i;
	SG_treenode* pTreenode = NULL;
    const char* psz_gid = NULL;
    SG_treenode_entry_type type;
    const char* psz_hid = NULL;

	SG_ERR_CHECK(  SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode)  );
	SG_ERR_CHECK(  SG_treenode__count(pCtx, pTreenode, &count)  );

	for (i=0; i<count; i++)
	{
		const SG_treenode_entry* pEntry = NULL;
		const char* pszName = NULL;

		SG_ERR_CHECK(  SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, i, &psz_gid, &pEntry)  );
		SG_ERR_CHECK(  SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName)  );

        SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pEntry, &type)  );
        SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pEntry, &psz_hid)  );

        if (SG_TREENODEENTRY_TYPE_DIRECTORY == type)
        {
            SG_ERR_CHECK(  sg_pack__do_blob(pCtx, psz_gid, psz_hid, gen, prb_blobs, prb_new)  );
            SG_ERR_CHECK(  sg_pack__get_dir(pCtx, pRepo, gen, psz_hid, prb_blobs, prb_new)  );
        }
        else if (SG_TREENODEENTRY_TYPE_REGULAR_FILE == type)
        {
            /* TODO use pszName file extension to decide whether to bother? */
            SG_ERR_CHECK(  sg_pack__do_blob(pCtx, psz_gid, psz_hid, gen, prb_blobs, prb_new)  );
        }
        else if (SG_TREENODEENTRY_TYPE_SYMLINK == type)
        {
            /* ignore symlinks */
        }
        else
        {
            SG_ERR_THROW(  SG_ERR_NOTIMPLEMENTED  );
        }
	}

	SG_TREENODE_NULLFREE(pCtx, pTreenode);
	pTreenode = NULL;

	return;

fail:
	SG_TREENODE_NULLFREE(pCtx, pTreenode);
}
示例#5
0
/**
 * This function is used to get a new tree.  It must be called with the HID of
 * the top-level user root directory.  Not the super-root.  The directory which
 * corresponds to @. */
static void sg_pack__do_get_dir__top(SG_context* pCtx, SG_repo* pRepo, SG_int32 gen, const char* pszidHidTreeNode, SG_rbtree* prb_blobs, SG_rbtree* prb_new)
{
	SG_treenode* pTreenode = NULL;
	SG_byte* pBytes = NULL;
    const SG_treenode_entry* pEntry = NULL;
    const char* pszidHidContent = NULL;

    /* Load the treenode.  It should have exactly one entry, a subdirectory,
     * named @ */
	SG_ERR_CHECK(  SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode)  );
    SG_ERR_CHECK(  SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, 0, NULL, &pEntry)  );
    SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pEntry, &pszidHidContent)  );

#ifdef DEBUG
    {
        SG_uint32 count;
        SG_treenode_entry_type type;
        const char* pszName = NULL;

        SG_ERR_CHECK(  SG_treenode__count(pCtx, pTreenode, &count)  );
        SG_ASSERT(1 == count);

		SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pEntry, &type)  );
		SG_ASSERT (SG_TREENODEENTRY_TYPE_DIRECTORY == type);

		SG_ERR_CHECK(  SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName)  );
        SG_ASSERT(0 == strcmp(pszName, "@"));
    }
#endif

    /* create the directory and then dive into it */
    SG_ERR_CHECK(  sg_pack__get_dir(pCtx, pRepo, gen, pszidHidContent, prb_blobs, prb_new)  );

	SG_TREENODE_NULLFREE(pCtx, pTreenode);

	return;

fail:
	/* TODO free stuff */
	SG_NULLFREE(pCtx, pBytes);
}
/**
 * BIND the fields for an INSERT or UPDATE a single row for this TreeNodeEntry (not
 * recursive) to the tne_L0 table.  Caller must compute the
 * GID aliases for the foreign keys and have already added
 * rows to tbl_gid as necessary.
 */
void sg_wc_db__tne__bind_insert(SG_context * pCtx,
								sqlite3_stmt * pStmt,
								SG_uint64 uiAliasGid,
								SG_uint64 uiAliasGidParent,
								const SG_treenode_entry * pTreenodeEntry)
{
	const char * pszHid = NULL;				// we do not own this
	const char * pszEntryname = NULL;		// we do not own this
	SG_int64 attrbits;
	SG_treenode_entry_type tneType;

	// pull all of the fields from the TNE.

	SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pTreenodeEntry, &pszHid)  );
	SG_ERR_CHECK(  SG_treenode_entry__get_entry_name(pCtx, pTreenodeEntry, &pszEntryname)  );
	SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pTreenodeEntry, &tneType)  );
	SG_ERR_CHECK(  SG_treenode_entry__get_attribute_bits(pCtx, pTreenodeEntry, &attrbits)  );

#if TRACE_WC_ATTRBITS
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
				   "TNE: bind_insert (%d) %s\n",
				   ((SG_uint32)attrbits),
				   pszEntryname)  );
#endif

	SG_ERR_CHECK(  sg_sqlite__reset(pCtx, pStmt)  );
	SG_ERR_CHECK(  sg_sqlite__clear_bindings(pCtx, pStmt)  );
	SG_ERR_CHECK(  sg_sqlite__bind_int64(          pCtx, pStmt, 1, uiAliasGid)  );
	SG_ERR_CHECK(  sg_sqlite__bind_int64(          pCtx, pStmt, 2, uiAliasGidParent)  );
	SG_ERR_CHECK(  sg_sqlite__bind_text__transient(pCtx, pStmt, 3, pszHid)  );
	SG_ERR_CHECK(  sg_sqlite__bind_int(            pCtx, pStmt, 4, tneType)  );
	SG_ERR_CHECK(  sg_sqlite__bind_int64(          pCtx, pStmt, 5, attrbits)  );
	SG_ERR_CHECK(  sg_sqlite__bind_text__transient(pCtx, pStmt, 6, pszEntryname)  );

fail:
	return;
}
示例#7
0
/**
 * This function is used to get a new tree.  It must be called with the HID of
 * the top-level user root directory.  Not the super-root.  The directory which
 * corresponds to @.
 *
 * Record the file timestamp of each file we fetch in the pvhTimestamps; this
 * provides the basis for the timestamp check in scan-dir.
 */
static void sg_workingdir__do_get_dir__top(SG_context* pCtx,
										   SG_repo* pRepo,
										   const SG_pathname* pPathLocal,
										   const char* pszidHidTreeNode,
										   SG_vhash * pvhTimestamps)
{
	SG_pathname* pPathSub = NULL;
	SG_treenode* pTreenode = NULL;
	SG_string* pstrLink = NULL;
	SG_byte* pBytes = NULL;
    SG_vhash* pvhAttributes = NULL;
    SG_int64 iAttributeBits = 0;
    const SG_treenode_entry* pEntry = NULL;
    const char* pszidHidContent = NULL;
#ifdef SG_BUILD_FLAG_FEATURE_XATTR
    const char* pszidHidXattrs = NULL;
#endif
	SG_bool bExists = SG_FALSE;

    /* Load the treenode.  It should have exactly one entry, a subdirectory,
     * named @ */
	SG_ERR_CHECK(  SG_treenode__load_from_repo(pCtx, pRepo, pszidHidTreeNode, &pTreenode)  );
    SG_ERR_CHECK(  SG_treenode__get_nth_treenode_entry__ref(pCtx, pTreenode, 0, NULL, &pEntry)  );
    SG_ERR_CHECK(  SG_treenode_entry__get_hid_blob(pCtx, pEntry, &pszidHidContent)  );

#ifdef DEBUG
    {
        SG_uint32 count;
        SG_treenode_entry_type type;
        const char* pszName = NULL;

        SG_ERR_CHECK(  SG_treenode__count(pCtx, pTreenode, &count)  );
        SG_ASSERT(1 == count);

		SG_ERR_CHECK(  SG_treenode_entry__get_entry_type(pCtx, pEntry, &type)  );
		SG_ASSERT (SG_TREENODEENTRY_TYPE_DIRECTORY == type);

		SG_ERR_CHECK(  SG_treenode_entry__get_entry_name(pCtx, pEntry, &pszName)  );
        SG_ASSERT(0 == strcmp(pszName, "@"));
    }
#endif

    /* create the directory and then dive into it */
    SG_ERR_CHECK(  SG_PATHNAME__ALLOC__COPY(pCtx, &pPathSub, pPathLocal)  );
	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx, pPathSub, &bExists, NULL, NULL)  );
	if (!bExists)
		SG_ERR_CHECK(  SG_fsobj__mkdir__pathname(pCtx, pPathSub)  );
    SG_ERR_CHECK(  _sg_workingdir__get_dir(pCtx, pRepo, pPathSub, pszidHidContent, pvhTimestamps)  );

#ifdef SG_BUILD_FLAG_FEATURE_XATTR
    /* fix up the xattrs on that directory */
    SG_ERR_CHECK(  SG_treenode_entry__get_hid_xattrs(pCtx, pEntry, &pszidHidXattrs)  );
    if (pszidHidXattrs)
    {
        SG_ERR_CHECK(  SG_repo__fetch_vhash(pCtx, pRepo, pszidHidXattrs, &pvhAttributes)  );
        SG_ERR_CHECK(  SG_attributes__xattrs__apply(pCtx, pPathSub, pvhAttributes, pRepo)  );
        SG_VHASH_NULLFREE(pCtx, pvhAttributes);
    }
#endif

    /* and the attrbits too */
    SG_ERR_CHECK(  SG_treenode_entry__get_attribute_bits(pCtx, pEntry, &iAttributeBits)  );
    SG_ERR_CHECK(  SG_attributes__bits__apply(pCtx, pPathSub, iAttributeBits)  );

    SG_PATHNAME_NULLFREE(pCtx, pPathSub);
	SG_TREENODE_NULLFREE(pCtx, pTreenode);

	return;
fail:
	/* TODO free stuff */
    SG_VHASH_NULLFREE(pCtx, pvhAttributes);
	SG_NULLFREE(pCtx, pBytes);
	SG_STRING_NULLFREE(pCtx, pstrLink);
}