{"action":"created","comment":{"url":"https://api.github.com/repos/etoile/CoreObject/pulls/comments/40279255","id":40279255,"diff_hunk":"@@ -662,57 +662,78 @@ - (BOOL) deleteRevids: (NSIndexSet *)revids\n     }\n \n     // Debugging:\n-//    NSLog(@\"In response to delete %@\", revids);\n-//    FMResultSet *rs = [db_ executeQuery: @\"SELECT revid, deltabase FROM commits WHERE deltabase IN (SELECT deltabase FROM commits GROUP BY deltabase HAVING garbage = 1)\"];\n-//    while ([rs next])\n-//    {\n-//        NSLog(@\"Deleting %d (db: %d)\", [rs intForColumnIndex:0], [rs intForColumnIndex: 1]);\n-//    }\n-//    [rs close];\n-    \n-    // For each delta base, delete the contiguous range of garbage revids starting at the maximum\n-    // and extending down to the first non-garbage revid\n-    \n+\t\n     // Example which can be pasted in the sqlite3 prompt to experiment with this query:\n     \n     /*\n      \n      drop table c;\n-     create table c (revid integer, deltabase integer, garbage boolean);\n-     \n-     insert into c values(0,0,0);\n-     insert into c values(1,0,1); -- marked as garbage, will be selected for deletion\n-     \n-     insert into c values(2,2,1); -- marked as garbage, will be selected for deletion\n-     insert into c values(3,2,1); -- marked as garbage, will be selected for deletion\n+     create table c (revid integer, deltabase integer, parent integer, garbage boolean);\n      \n-     insert into c values(4,4,0);\n-     insert into c values(5,4,0);\n+     insert into c values(0,0,-1,0);\n+     insert into c values(1,0,0,1); -- marked as garbage, will be selected for deletion\n      \n-     insert into c values(6,6,0);\n-     insert into c values(7,6,1); -- marked as garbage, won't be deleted because there are higher non-garbage revids in this delta run\n-     insert into c values(8,6,0);\n+     insert into c values(2,2,1,1); -- marked as garbage, will be selected for deletion\n+     insert into c values(3,2,2,1); -- marked as garbage, will be selected for deletion\n      \n-     SELECT commits.revid\n-     FROM c AS commits\n-     LEFT OUTER JOIN (SELECT deltabase, MAX(revid) AS maxkeptrevid FROM c WHERE garbage = 0 GROUP BY deltabase) AS info\n-     USING (deltabase)\n-     WHERE (commits.revid > info.maxkeptrevid) OR info.maxkeptrevid IS NULL;\n+     insert into c values(4,4,3,0);\n+     insert into c values(5,4,4,0);\n      \n-     -- The \"OR info.maxkeptrevid IS NULL\" part is so that we delete all commits in delta runs where all commits are garbage.\n+     insert into c values(6,6,5,0);\n+     insert into c values(7,6,6,1); -- marked as garbage, will be selected for deletion\n+     insert into c values(8,6,7,0); -- will be rebuit because it's not a full snapshot, but its parent is being deleted\n      \n+\t \n+\t -- Identifies the revisions that need to be rebuilt:\n+\t \n+\t SELECT revid\n+\t FROM c\n+\t LEFT OUTER JOIN (SELECT garbage AS parentgarbage, revid AS parentrevid FROM c)\n+\t ON (parent = parentrevid)\n+\t WHERE garbage = 0 AND parentgarbage = 1 AND deltabase != revid;\n+\t \n      */\n-    \n-    // Could be done at a later time\n-    [db_ executeUpdate: [NSString stringWithFormat: @\"DELETE FROM %@ WHERE revid IN (SELECT commits.revid \"\n-                         \"FROM %@ AS commits \"\n-                         \"LEFT OUTER JOIN (SELECT deltabase, MAX(revid) AS maxkeptrevid FROM %@ WHERE garbage = 0 GROUP BY deltabase) AS info \"\n-                         \"USING (deltabase) \"\n-                         \"WHERE (commits.revid > info.maxkeptrevid) OR info.maxkeptrevid IS NULL)\",\n-                         [self tableName], [self tableName], [self tableName]]];\n-    \n-    // TODO: Vacuum here?\n-    \n+\t\n+\t// Gather the set of revids that need to be rebuilt\n+\tNSMutableIndexSet *rebuildRevids = [NSMutableIndexSet indexSet];\n+\tFMResultSet *rs = [db_ executeQuery: [NSString stringWithFormat:\n+\t\t\t\t\t\t\t\t\t\t  @\"SELECT revid \"\n+\t\t\t\t\t\t\t\t\t\t  \"FROM %@ \"\n+\t\t\t\t\t\t\t\t\t\t  \"LEFT OUTER JOIN (SELECT garbage AS parentgarbage, revid AS parentrevid FROM %@) \"\n+\t\t\t\t\t\t\t\t\t\t  \"ON (parent = parentrevid) \"\n+\t\t\t\t\t\t\t\t\t\t  \"WHERE garbage = 0 AND parentgarbage = 1 AND deltabase != revid\", [self tableName], [self tableName]]];\n+\twhile ([rs next])\n+\t{\n+\t\t[rebuildRevids addIndex: [rs longLongIntForColumnIndex: 0]];\n+\t}\n+\t[rs close];\n+\t\n+\t// Rebuild each revision that needs it\n+\t[rebuildRevids enumerateIndexesUsingBlock: ^(NSUInteger revid, BOOL *stop){\n+\t\tCOItemGraph *graph = [self itemGraphForRevid: revid];\n+\t\t\n+\t\t// GC unreachable items in graph\n+\t\t[graph removeUnreachableItems];\n+\t\t\n+\t\tNSData *contentsBlob = contentsBLOBWithItemTree(graph);\n+\t\t\n+\t\tBOOL ok = [db_ executeUpdate: [NSString stringWithFormat: @\"UPDATE %@ SET contents = ?, hash = ?, deltabase = ?, bytesInDeltaRun = ? WHERE revid = ?\", [self tableName]],\n+\t\t\t\t   /* contents        */ contentsBlob,\n+\t\t\t\t   /* hash            */ Sha1Data(contentsBlob),\n+\t\t\t\t   /* deltabase       */ @(revid),\n+\t\t\t\t   /* bytesInDeltaRun */ @([contentsBlob length]),\n+\t\t\t\t   /* revid           */ @(revid)];\n+\n+\t\tif (!ok)\n+\t\t{\n+\t\t\t[db_ rollback];","path":"Store/COSQLiteStorePersistentRootBackingStore.m","position":117,"original_position":117,"commit_id":"ba3961f35241fb94bb9474761499a7d3d35d24f2","original_commit_id":"ba3961f35241fb94bb9474761499a7d3d35d24f2","user":{"login":"ericwa","id":239161,"avatar_url":"https://avatars.githubusercontent.com/u/239161?v=3","gravatar_id":"","url":"https://api.github.com/users/ericwa","html_url":"https://github.com/ericwa","followers_url":"https://api.github.com/users/ericwa/followers","following_url":"https://api.github.com/users/ericwa/following{/other_user}","gists_url":"https://api.github.com/users/ericwa/gists{/gist_id}","starred_url":"https://api.github.com/users/ericwa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ericwa/subscriptions","organizations_url":"https://api.github.com/users/ericwa/orgs","repos_url":"https://api.github.com/users/ericwa/repos","events_url":"https://api.github.com/users/ericwa/events{/privacy}","received_events_url":"https://api.github.com/users/ericwa/received_events","type":"User","site_admin":false},"body":"The transaction wouldn't be committed unless we get to the -commit call, so the DB wouldn't be corrupted.","created_at":"2015-09-24T01:57:08Z","updated_at":"2015-09-24T01:57:08Z","html_url":"https://github.com/etoile/CoreObject/pull/26#discussion_r40279255","pull_request_url":"https://api.github.com/repos/etoile/CoreObject/pulls/26","_links":{"self":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/comments/40279255"},"html":{"href":"https://github.com/etoile/CoreObject/pull/26#discussion_r40279255"},"pull_request":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/26"}}},"pull_request":{"url":"https://api.github.com/repos/etoile/CoreObject/pulls/26","id":45730267,"html_url":"https://github.com/etoile/CoreObject/pull/26","diff_url":"https://github.com/etoile/CoreObject/pull/26.diff","patch_url":"https://github.com/etoile/CoreObject/pull/26.patch","issue_url":"https://api.github.com/repos/etoile/CoreObject/issues/26","number":26,"state":"open","locked":false,"title":"Store/COSQLiteStorePersistentRootBackingStore.m: Change deletion semantics for -deleteRevids:.","user":{"login":"ericwa","id":239161,"avatar_url":"https://avatars.githubusercontent.com/u/239161?v=3","gravatar_id":"","url":"https://api.github.com/users/ericwa","html_url":"https://github.com/ericwa","followers_url":"https://api.github.com/users/ericwa/followers","following_url":"https://api.github.com/users/ericwa/following{/other_user}","gists_url":"https://api.github.com/users/ericwa/gists{/gist_id}","starred_url":"https://api.github.com/users/ericwa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ericwa/subscriptions","organizations_url":"https://api.github.com/users/ericwa/orgs","repos_url":"https://api.github.com/users/ericwa/repos","events_url":"https://api.github.com/users/ericwa/events{/privacy}","received_events_url":"https://api.github.com/users/ericwa/received_events","type":"User","site_admin":false},"body":"Now all given revids are guaranteed to be deleted from the backing store.\r\nIf there any child revisions of the revisions being deleted which are deltas, turns them into full snapshots so they aren't corrupted.\r\n\r\nThe test case simulates an example David posted where you want to make sure a password is deleted from the store.\r\n\r\nTests/Store/TestSQLiteBackingStore.m: Start a backing store test case","created_at":"2015-09-22T23:34:11Z","updated_at":"2015-09-24T01:57:08Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bfd33dad8a961c608605660db70cc8a2ba957a0f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/etoile/CoreObject/pulls/26/commits","review_comments_url":"https://api.github.com/repos/etoile/CoreObject/pulls/26/comments","review_comment_url":"https://api.github.com/repos/etoile/CoreObject/pulls/comments{/number}","comments_url":"https://api.github.com/repos/etoile/CoreObject/issues/26/comments","statuses_url":"https://api.github.com/repos/etoile/CoreObject/statuses/ba3961f35241fb94bb9474761499a7d3d35d24f2","head":{"label":"etoile:backingstore-deletion","ref":"backingstore-deletion","sha":"ba3961f35241fb94bb9474761499a7d3d35d24f2","user":{"login":"etoile","id":641984,"avatar_url":"https://avatars.githubusercontent.com/u/641984?v=3","gravatar_id":"","url":"https://api.github.com/users/etoile","html_url":"https://github.com/etoile","followers_url":"https://api.github.com/users/etoile/followers","following_url":"https://api.github.com/users/etoile/following{/other_user}","gists_url":"https://api.github.com/users/etoile/gists{/gist_id}","starred_url":"https://api.github.com/users/etoile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etoile/subscriptions","organizations_url":"https://api.github.com/users/etoile/orgs","repos_url":"https://api.github.com/users/etoile/repos","events_url":"https://api.github.com/users/etoile/events{/privacy}","received_events_url":"https://api.github.com/users/etoile/received_events","type":"Organization","site_admin":false},"repo":{"id":15001136,"name":"CoreObject","full_name":"etoile/CoreObject","owner":{"login":"etoile","id":641984,"avatar_url":"https://avatars.githubusercontent.com/u/641984?v=3","gravatar_id":"","url":"https://api.github.com/users/etoile","html_url":"https://github.com/etoile","followers_url":"https://api.github.com/users/etoile/followers","following_url":"https://api.github.com/users/etoile/following{/other_user}","gists_url":"https://api.github.com/users/etoile/gists{/gist_id}","starred_url":"https://api.github.com/users/etoile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etoile/subscriptions","organizations_url":"https://api.github.com/users/etoile/orgs","repos_url":"https://api.github.com/users/etoile/repos","events_url":"https://api.github.com/users/etoile/events{/privacy}","received_events_url":"https://api.github.com/users/etoile/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/etoile/CoreObject","description":"Distributed version control + object persistence framework ","fork":false,"url":"https://api.github.com/repos/etoile/CoreObject","forks_url":"https://api.github.com/repos/etoile/CoreObject/forks","keys_url":"https://api.github.com/repos/etoile/CoreObject/keys{/key_id}","collaborators_url":"https://api.github.com/repos/etoile/CoreObject/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/etoile/CoreObject/teams","hooks_url":"https://api.github.com/repos/etoile/CoreObject/hooks","issue_events_url":"https://api.github.com/repos/etoile/CoreObject/issues/events{/number}","events_url":"https://api.github.com/repos/etoile/CoreObject/events","assignees_url":"https://api.github.com/repos/etoile/CoreObject/assignees{/user}","branches_url":"https://api.github.com/repos/etoile/CoreObject/branches{/branch}","tags_url":"https://api.github.com/repos/etoile/CoreObject/tags","blobs_url":"https://api.github.com/repos/etoile/CoreObject/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/etoile/CoreObject/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/etoile/CoreObject/git/refs{/sha}","trees_url":"https://api.github.com/repos/etoile/CoreObject/git/trees{/sha}","statuses_url":"https://api.github.com/repos/etoile/CoreObject/statuses/{sha}","languages_url":"https://api.github.com/repos/etoile/CoreObject/languages","stargazers_url":"https://api.github.com/repos/etoile/CoreObject/stargazers","contributors_url":"https://api.github.com/repos/etoile/CoreObject/contributors","subscribers_url":"https://api.github.com/repos/etoile/CoreObject/subscribers","subscription_url":"https://api.github.com/repos/etoile/CoreObject/subscription","commits_url":"https://api.github.com/repos/etoile/CoreObject/commits{/sha}","git_commits_url":"https://api.github.com/repos/etoile/CoreObject/git/commits{/sha}","comments_url":"https://api.github.com/repos/etoile/CoreObject/comments{/number}","issue_comment_url":"https://api.github.com/repos/etoile/CoreObject/issues/comments{/number}","contents_url":"https://api.github.com/repos/etoile/CoreObject/contents/{+path}","compare_url":"https://api.github.com/repos/etoile/CoreObject/compare/{base}...{head}","merges_url":"https://api.github.com/repos/etoile/CoreObject/merges","archive_url":"https://api.github.com/repos/etoile/CoreObject/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/etoile/CoreObject/downloads","issues_url":"https://api.github.com/repos/etoile/CoreObject/issues{/number}","pulls_url":"https://api.github.com/repos/etoile/CoreObject/pulls{/number}","milestones_url":"https://api.github.com/repos/etoile/CoreObject/milestones{/number}","notifications_url":"https://api.github.com/repos/etoile/CoreObject/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/etoile/CoreObject/labels{/name}","releases_url":"https://api.github.com/repos/etoile/CoreObject/releases{/id}","created_at":"2013-12-07T06:34:10Z","updated_at":"2015-09-01T13:38:15Z","pushed_at":"2015-09-23T18:15:45Z","git_url":"git://github.com/etoile/CoreObject.git","ssh_url":"git@github.com:etoile/CoreObject.git","clone_url":"https://github.com/etoile/CoreObject.git","svn_url":"https://github.com/etoile/CoreObject","homepage":"http://coreobject.org","size":22336,"stargazers_count":260,"watchers_count":260,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":11,"mirror_url":null,"open_issues_count":4,"forks":11,"open_issues":4,"watchers":260,"default_branch":"master"}},"base":{"label":"etoile:master","ref":"master","sha":"4d17201fcd4a9aa2a602702253b42b0b82c8ac12","user":{"login":"etoile","id":641984,"avatar_url":"https://avatars.githubusercontent.com/u/641984?v=3","gravatar_id":"","url":"https://api.github.com/users/etoile","html_url":"https://github.com/etoile","followers_url":"https://api.github.com/users/etoile/followers","following_url":"https://api.github.com/users/etoile/following{/other_user}","gists_url":"https://api.github.com/users/etoile/gists{/gist_id}","starred_url":"https://api.github.com/users/etoile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etoile/subscriptions","organizations_url":"https://api.github.com/users/etoile/orgs","repos_url":"https://api.github.com/users/etoile/repos","events_url":"https://api.github.com/users/etoile/events{/privacy}","received_events_url":"https://api.github.com/users/etoile/received_events","type":"Organization","site_admin":false},"repo":{"id":15001136,"name":"CoreObject","full_name":"etoile/CoreObject","owner":{"login":"etoile","id":641984,"avatar_url":"https://avatars.githubusercontent.com/u/641984?v=3","gravatar_id":"","url":"https://api.github.com/users/etoile","html_url":"https://github.com/etoile","followers_url":"https://api.github.com/users/etoile/followers","following_url":"https://api.github.com/users/etoile/following{/other_user}","gists_url":"https://api.github.com/users/etoile/gists{/gist_id}","starred_url":"https://api.github.com/users/etoile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etoile/subscriptions","organizations_url":"https://api.github.com/users/etoile/orgs","repos_url":"https://api.github.com/users/etoile/repos","events_url":"https://api.github.com/users/etoile/events{/privacy}","received_events_url":"https://api.github.com/users/etoile/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/etoile/CoreObject","description":"Distributed version control + object persistence framework ","fork":false,"url":"https://api.github.com/repos/etoile/CoreObject","forks_url":"https://api.github.com/repos/etoile/CoreObject/forks","keys_url":"https://api.github.com/repos/etoile/CoreObject/keys{/key_id}","collaborators_url":"https://api.github.com/repos/etoile/CoreObject/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/etoile/CoreObject/teams","hooks_url":"https://api.github.com/repos/etoile/CoreObject/hooks","issue_events_url":"https://api.github.com/repos/etoile/CoreObject/issues/events{/number}","events_url":"https://api.github.com/repos/etoile/CoreObject/events","assignees_url":"https://api.github.com/repos/etoile/CoreObject/assignees{/user}","branches_url":"https://api.github.com/repos/etoile/CoreObject/branches{/branch}","tags_url":"https://api.github.com/repos/etoile/CoreObject/tags","blobs_url":"https://api.github.com/repos/etoile/CoreObject/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/etoile/CoreObject/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/etoile/CoreObject/git/refs{/sha}","trees_url":"https://api.github.com/repos/etoile/CoreObject/git/trees{/sha}","statuses_url":"https://api.github.com/repos/etoile/CoreObject/statuses/{sha}","languages_url":"https://api.github.com/repos/etoile/CoreObject/languages","stargazers_url":"https://api.github.com/repos/etoile/CoreObject/stargazers","contributors_url":"https://api.github.com/repos/etoile/CoreObject/contributors","subscribers_url":"https://api.github.com/repos/etoile/CoreObject/subscribers","subscription_url":"https://api.github.com/repos/etoile/CoreObject/subscription","commits_url":"https://api.github.com/repos/etoile/CoreObject/commits{/sha}","git_commits_url":"https://api.github.com/repos/etoile/CoreObject/git/commits{/sha}","comments_url":"https://api.github.com/repos/etoile/CoreObject/comments{/number}","issue_comment_url":"https://api.github.com/repos/etoile/CoreObject/issues/comments{/number}","contents_url":"https://api.github.com/repos/etoile/CoreObject/contents/{+path}","compare_url":"https://api.github.com/repos/etoile/CoreObject/compare/{base}...{head}","merges_url":"https://api.github.com/repos/etoile/CoreObject/merges","archive_url":"https://api.github.com/repos/etoile/CoreObject/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/etoile/CoreObject/downloads","issues_url":"https://api.github.com/repos/etoile/CoreObject/issues{/number}","pulls_url":"https://api.github.com/repos/etoile/CoreObject/pulls{/number}","milestones_url":"https://api.github.com/repos/etoile/CoreObject/milestones{/number}","notifications_url":"https://api.github.com/repos/etoile/CoreObject/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/etoile/CoreObject/labels{/name}","releases_url":"https://api.github.com/repos/etoile/CoreObject/releases{/id}","created_at":"2013-12-07T06:34:10Z","updated_at":"2015-09-01T13:38:15Z","pushed_at":"2015-09-23T18:15:45Z","git_url":"git://github.com/etoile/CoreObject.git","ssh_url":"git@github.com:etoile/CoreObject.git","clone_url":"https://github.com/etoile/CoreObject.git","svn_url":"https://github.com/etoile/CoreObject","homepage":"http://coreobject.org","size":22336,"stargazers_count":260,"watchers_count":260,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":11,"mirror_url":null,"open_issues_count":4,"forks":11,"open_issues":4,"watchers":260,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/26"},"html":{"href":"https://github.com/etoile/CoreObject/pull/26"},"issue":{"href":"https://api.github.com/repos/etoile/CoreObject/issues/26"},"comments":{"href":"https://api.github.com/repos/etoile/CoreObject/issues/26/comments"},"review_comments":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/26/comments"},"review_comment":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/etoile/CoreObject/pulls/26/commits"},"statuses":{"href":"https://api.github.com/repos/etoile/CoreObject/statuses/ba3961f35241fb94bb9474761499a7d3d35d24f2"}}}}