// TODO consider the possible perf benefits of changing this routine // to accept lots of changeset ids instead of just one, so it // can handle them all at once. void SG_treendx__update__multiple( SG_context* pCtx, SG_treendx* pTreeNdx, SG_stringarray* psa ) { SG_changeset* pcs = NULL; sqlite3_stmt* pStmt = NULL; SG_vhash* pvh_treepaths = NULL; SG_uint32 count_treepaths = 0; SG_uint32 count_changesets = 0; SG_uint32 ics = 0; SG_NULLARGCHECK_RETURN(psa); SG_NULLARGCHECK_RETURN(pTreeNdx); SG_ERR_CHECK( SG_stringarray__count(pCtx, psa, &count_changesets) ); SG_ERR_CHECK( sg_sqlite__exec__va(pCtx, pTreeNdx->psql, "BEGIN TRANSACTION; ") ); SG_ERR_CHECK( sg_sqlite__prepare(pCtx, pTreeNdx->psql, &pStmt, "INSERT OR IGNORE INTO treendx (gid, strpath) VALUES (?, ?)") ); for (ics=0; ics<count_changesets; ics++) { const char* psz_hid = NULL; SG_uint32 i = 0; SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, psa, ics, &psz_hid) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pTreeNdx->pRepo, psz_hid, &pcs) ); SG_ERR_CHECK( SG_changeset__get_treepaths(pCtx, pcs, &pvh_treepaths) ); if (pvh_treepaths) { SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_treepaths, &count_treepaths) ); for (i=0; i<count_treepaths; i++) { const char* psz_gid = NULL; const SG_variant* pv = NULL; const char* psz_path = NULL; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_treepaths, i, &psz_gid, &pv) ); SG_ERR_CHECK( SG_variant__get__sz(pCtx, pv, &psz_path) ); SG_ERR_CHECK( sg_sqlite__reset(pCtx, pStmt) ); SG_ERR_CHECK( sg_sqlite__clear_bindings(pCtx, pStmt) ); SG_ERR_CHECK( sg_sqlite__bind_text(pCtx, pStmt, 1, psz_gid) ); SG_ERR_CHECK( sg_sqlite__bind_text(pCtx, pStmt, 2, psz_path) ); SG_ERR_CHECK( sg_sqlite__step(pCtx, pStmt, SQLITE_DONE) ); } } SG_CHANGESET_NULLFREE(pCtx, pcs); } SG_ERR_CHECK( sg_sqlite__nullfinalize(pCtx, &pStmt) ); SG_ERR_CHECK( sg_sqlite__exec__va(pCtx, pTreeNdx->psql, "COMMIT TRANSACTION; ") ); fail: SG_CHANGESET_NULLFREE(pCtx, pcs); }
void SG_treendx__get_path_in_dagnode(SG_context* pCtx, SG_treendx* pTreeNdx, const char* psz_search_item_gid, const char* psz_changeset, SG_treenode_entry ** ppTreeNodeEntry) { SG_rbtree_iterator * rb_it = NULL; const char * pPath = NULL; SG_changeset * pChangeset = NULL; SG_stringarray * pPaths = NULL; const char* pszHidTreeNode = NULL; SG_treenode * pTreenodeRoot = NULL; char* pszReturnedGID = NULL; SG_uint32 i = 0; SG_uint32 count = 0; SG_ERR_CHECK_RETURN( SG_gid__argcheck(pCtx, psz_search_item_gid) ); SG_ERR_CHECK( SG_treendx__get_all_paths(pCtx, pTreeNdx, psz_search_item_gid, &pPaths) ); *ppTreeNodeEntry = NULL; SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pTreeNdx->pRepo, psz_changeset, &pChangeset) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pChangeset, &pszHidTreeNode) ); SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pTreeNdx->pRepo, pszHidTreeNode, &pTreenodeRoot) ); SG_ERR_CHECK( SG_stringarray__count(pCtx, pPaths, &count ) ); for (i = 0; i < count; i++) { SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, pPaths, i, &pPath) ); SG_ERR_CHECK( SG_treenode__find_treenodeentry_by_path(pCtx, pTreeNdx->pRepo, pTreenodeRoot, pPath, &pszReturnedGID, ppTreeNodeEntry) ); if (*ppTreeNodeEntry != NULL && strcmp(pszReturnedGID, psz_search_item_gid) == 0) { break; } else if (*ppTreeNodeEntry != NULL) { SG_TREENODE_ENTRY_NULLFREE(pCtx, *ppTreeNodeEntry); *ppTreeNodeEntry = NULL; //It's not the right GID, even though it's in the right spot. } } SG_NULLFREE(pCtx, pszReturnedGID); SG_CHANGESET_NULLFREE(pCtx, pChangeset); SG_TREENODE_NULLFREE(pCtx, pTreenodeRoot); SG_STRINGARRAY_NULLFREE(pCtx, pPaths); SG_RBTREE_ITERATOR_NULLFREE(pCtx, rb_it); return; fail: SG_NULLFREE(pCtx, pszReturnedGID); SG_CHANGESET_NULLFREE(pCtx, pChangeset); SG_STRINGARRAY_NULLFREE(pCtx, pPaths); SG_RBTREE_ITERATOR_NULLFREE(pCtx, rb_it); return; }
static void _do_since( SG_context* pCtx, SG_repo* pRepo, SG_vhash* pvh_since, SG_fragball_writer* pfb ) { SG_uint32 count_dagnums = 0; SG_uint32 i_dagnum = 0; SG_ihash* pih_new = NULL; SG_rbtree* prb = NULL; SG_vhash* pvh_blobs = NULL; SG_changeset* pcs = NULL; SG_NULLARGCHECK_RETURN(pRepo); SG_NULLARGCHECK_RETURN(pvh_since); SG_NULLARGCHECK_RETURN(pfb); // TODO do we need to deal with dags which are present here but not in pvh_since? SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_since, &count_dagnums) ); for (i_dagnum=0; i_dagnum<count_dagnums; i_dagnum++) { const char* psz_dagnum = NULL; SG_varray* pva_nodes = NULL; SG_uint64 dagnum = 0; SG_ERR_CHECK( SG_vhash__get_nth_pair__varray(pCtx, pvh_since, i_dagnum, &psz_dagnum, &pva_nodes) ); SG_ERR_CHECK( SG_dagnum__from_sz__hex(pCtx, psz_dagnum, &dagnum) ); SG_ERR_CHECK( SG_repo__find_new_dagnodes_since(pCtx, pRepo, dagnum, pva_nodes, &pih_new) ); if (pih_new) { SG_uint32 count = 0; SG_ERR_CHECK( SG_ihash__count(pCtx, pih_new, &count) ); if (count) { SG_uint32 i = 0; SG_ERR_CHECK( SG_rbtree__alloc(pCtx, &prb) ); SG_ERR_CHECK( SG_vhash__alloc(pCtx, &pvh_blobs) ); for (i=0; i<count; i++) { const char* psz_node = NULL; SG_ERR_CHECK( SG_ihash__get_nth_pair(pCtx, pih_new, i, &psz_node, NULL) ); SG_ERR_CHECK( SG_rbtree__add(pCtx, prb, psz_node) ); SG_ERR_CHECK( SG_vhash__add__null(pCtx, pvh_blobs, psz_node) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_node, &pcs) ); SG_ERR_CHECK( _add_necessary_blobs(pCtx, pcs, pvh_blobs) ); SG_CHANGESET_NULLFREE(pCtx, pcs); } // put all these new nodes in the frag SG_ERR_CHECK( SG_fragball__write__dagnodes(pCtx, pfb, dagnum, prb) ); // and the blobs SG_ERR_CHECK( SG_sync__add_blobs_to_fragball(pCtx, pfb, pvh_blobs) ); SG_VHASH_NULLFREE(pCtx, pvh_blobs); SG_RBTREE_NULLFREE(pCtx, prb); } SG_IHASH_NULLFREE(pCtx, pih_new); } } fail: SG_CHANGESET_NULLFREE(pCtx, pcs); SG_VHASH_NULLFREE(pCtx, pvh_blobs); SG_RBTREE_NULLFREE(pCtx, prb); SG_IHASH_NULLFREE(pCtx, pih_new); }
void SG_workingdir__create_and_get( SG_context* pCtx, const char* pszDescriptorName, const SG_pathname* pPathDirPutTopLevelDirInHere, SG_bool bCreateDrawer, const char* psz_spec_hid_cs_baseline ) { SG_repo* pRepo = NULL; SG_rbtree* pIdsetLeaves = NULL; SG_uint32 count_leaves = 0; SG_changeset* pcs = NULL; const char* pszidUserSuperRoot = NULL; SG_bool b = SG_FALSE; char* psz_hid_cs_baseline = NULL; SG_pendingtree * pPendingTree = NULL; SG_vhash * pvhTimestamps = NULL; /* * Fetch the descriptor by its given name and use it to connect to * the repo. */ SG_ERR_CHECK( SG_repo__open_repo_instance(pCtx, pszDescriptorName, &pRepo) ); if (psz_spec_hid_cs_baseline) { SG_ERR_CHECK( SG_strdup(pCtx, psz_spec_hid_cs_baseline, &psz_hid_cs_baseline) ); } else { const char* psz_hid = NULL; /* * If you do not specify a hid to be the baseline, then this routine * currently only works if there is exactly one leaf in the repo. */ SG_ERR_CHECK( SG_repo__fetch_dag_leaves(pCtx, pRepo,SG_DAGNUM__VERSION_CONTROL,&pIdsetLeaves) ); SG_ERR_CHECK( SG_rbtree__count(pCtx, pIdsetLeaves, &count_leaves) ); if (count_leaves != 1) SG_ERR_THROW( SG_ERR_MULTIPLE_HEADS_FROM_DAGNODE ); SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, NULL, pIdsetLeaves, &b, &psz_hid, NULL) ); SG_ERR_CHECK( SG_STRDUP(pCtx, psz_hid, &psz_hid_cs_baseline) ); } /* * Load the desired changeset from the repo so we can look up the * id of its user root directory */ SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_hid_cs_baseline, &pcs) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pcs, &pszidUserSuperRoot) ); if (bCreateDrawer) { SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvhTimestamps) ); // Retrieve everything into the WD and capture the timestamps on the files that we create. SG_ERR_CHECK( sg_workingdir__do_get_dir__top(pCtx, pRepo, pPathDirPutTopLevelDirInHere, pszidUserSuperRoot, pvhTimestamps) ); // this creates "repo.json" with the repo-descriptor. SG_ERR_CHECK( SG_workingdir__set_mapping(pCtx, pPathDirPutTopLevelDirInHere, pszDescriptorName, NULL) ); // this creates an empty "wd.json" file (which doesn't know anything). SG_ERR_CHECK( SG_PENDINGTREE__ALLOC(pCtx, pPathDirPutTopLevelDirInHere, SG_TRUE, &pPendingTree) ); // force set the initial parents to the current changeset. SG_ERR_CHECK( SG_pendingtree__set_single_wd_parent(pCtx, pPendingTree, psz_hid_cs_baseline) ); // force initialize the timestamp cache to the list that we just built; this should // be the only timestamps in the cache since we just populated the WD. SG_ERR_CHECK( SG_pendingtree__set_wd_timestamp_cache(pCtx, pPendingTree, &pvhTimestamps) ); // this steals our vhash SG_ERR_CHECK( SG_pendingtree__save(pCtx, pPendingTree) ); } else { // Retrieve everything into the WD but do not create .sgdrawer or record timestamps. // This is more like an EXPORT operation. SG_ERR_CHECK( sg_workingdir__do_get_dir__top(pCtx, pRepo, pPathDirPutTopLevelDirInHere, pszidUserSuperRoot, NULL) ); } fail: SG_VHASH_NULLFREE(pCtx, pvhTimestamps); SG_NULLFREE(pCtx, psz_hid_cs_baseline); SG_CHANGESET_NULLFREE(pCtx, pcs); SG_RBTREE_NULLFREE(pCtx, pIdsetLeaves); SG_REPO_NULLFREE(pCtx, pRepo); SG_PENDINGTREE_NULLFREE(pCtx, pPendingTree); }
static void loop_innards_make_delta( SG_context* pCtx, SG_repo* pRepo, SG_varray* pva_path, SG_uint32 i_path_step, SG_vhash* pvh_add, SG_vhash* pvh_remove ) { SG_changeset* pcs = NULL; const char* psz_csid_cur = NULL; const char* psz_csid_parent = NULL; SG_vhash* pvh_changes = NULL; SG_vhash* pvh_one_parent_changes = NULL; SG_vhash* pvh_cs_add = NULL; SG_vhash* pvh_cs_remove = NULL; SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_path, i_path_step, &psz_csid_cur) ); SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_path, i_path_step + 1, &psz_csid_parent) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_csid_cur, &pcs) ); SG_ERR_CHECK( SG_changeset__db__get_changes(pCtx, pcs, &pvh_changes) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_changes, psz_csid_parent, &pvh_one_parent_changes) ); SG_ERR_CHECK( SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "add", &pvh_cs_remove) ); SG_ERR_CHECK( SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "remove", &pvh_cs_add) ); if (pvh_cs_add) { SG_uint32 count = 0; SG_uint32 i = 0; SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_cs_add, &count) ); for (i=0; i<count; i++) { const char* psz_hid_rec = NULL; SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_cs_add, i, &psz_hid_rec, NULL) ); SG_ERR_CHECK( SG_vhash__remove_if_present(pCtx, pvh_remove, psz_hid_rec, &b) ); if (!b) { SG_ERR_CHECK( SG_vhash__update__null(pCtx, pvh_add, psz_hid_rec) ); } } } if (pvh_cs_remove) { SG_uint32 count = 0; SG_uint32 i = 0; SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_cs_remove, &count) ); for (i=0; i<count; i++) { const char* psz_hid_rec = NULL; SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_cs_remove, i, &psz_hid_rec, NULL) ); SG_ERR_CHECK( SG_vhash__remove_if_present(pCtx, pvh_add, psz_hid_rec, &b) ); if (!b) { SG_ERR_CHECK( SG_vhash__update__null(pCtx, pvh_remove, psz_hid_rec) ); } } } fail: SG_CHANGESET_NULLFREE(pCtx, pcs); }
void sg_pack__do_changeset(SG_context* pCtx, SG_repo* pRepo, const char* psz_hid_cs, SG_rbtree* prb_blobs) { SG_changeset* pcs = NULL; SG_int32 gen = 0; SG_uint32 count_blobs = 0; SG_uint32 count_parents = 0; SG_varray* pva_parents = NULL; SG_uint32 i; SG_rbtree* prb_new = NULL; const char* psz_hid_root_treenode = NULL; const char* psz_key = NULL; SG_vhash* pvh_lbl = NULL; SG_vhash* pvh_blobs = NULL; SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_hid_cs, &pcs) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pcs, &psz_hid_root_treenode) ); SG_ERR_CHECK( SG_changeset__get_generation(pCtx, pcs, &gen) ); SG_ERR_CHECK( SG_RBTREE__ALLOC__PARAMS(pCtx, &prb_new, count_blobs, NULL) ); SG_ERR_CHECK( SG_changeset__get_list_of_bloblists(pCtx, pcs, &pvh_lbl) ); /* add all the tree user file blobs */ SG_ERR_CHECK( SG_changeset__get_bloblist_name(pCtx, SG_BLOB_REFTYPE__TREEUSERFILE, &psz_key) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_lbl, psz_key, &pvh_blobs) ); SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_blobs, &count_blobs) ); /* now write all the blobs */ for (i=0; i<count_blobs; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_blobs, i, &psz_hid, NULL) ); SG_ERR_CHECK( SG_rbtree__add(pCtx, prb_new, psz_hid) ); } /* and the treenode blobs */ SG_ERR_CHECK( SG_changeset__get_bloblist_name(pCtx, SG_BLOB_REFTYPE__TREENODE, &psz_key) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_lbl, psz_key, &pvh_blobs) ); SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_blobs, &count_blobs) ); /* now write all the blobs */ for (i=0; i<count_blobs; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_rbtree__add(pCtx, prb_new, psz_hid) ); } SG_ERR_CHECK( sg_pack__do_get_dir__top(pCtx, pRepo, gen, psz_hid_root_treenode, prb_blobs, prb_new) ); SG_RBTREE_NULLFREE(pCtx, prb_new); SG_ERR_CHECK( SG_changeset__get_parents(pCtx, pcs, &pva_parents) ); if (pva_parents) { SG_ERR_CHECK( SG_varray__count(pCtx, pva_parents, &count_parents) ); for (i=0; i<count_parents; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_parents, i, &psz_hid) ); SG_ERR_CHECK( sg_pack__do_changeset(pCtx, pRepo, psz_hid, prb_blobs) ); } } SG_CHANGESET_NULLFREE(pCtx, pcs); return; fail: SG_RBTREE_NULLFREE(pCtx, prb_new); }