{"action":"created","comment":{"url":"https://api.github.com/repos/apache/couchdb/pulls/comments/195283123","pull_request_review_id":128619081,"id":195283123,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NTI4MzEyMw==","diff_hunk":"@@ -298,6 +314,104 @@ with_db(DbName, Options, {M,F,A}) ->\n         rexi:reply(Error)\n     end.\n \n+\n+read_repair_filter(DbName, Docs, NodeRevs, Options) ->\n+    set_io_priority(DbName, Options),\n+    case get_or_create_db(DbName, Options) of\n+        {ok, Db} ->\n+            try\n+                read_repair_filter(Db, Docs, NodeRevs)\n+            after\n+                couch_db:close(Db)\n+            end;\n+        Error ->\n+            rexi:reply(Error)\n+    end.\n+\n+\n+% A read repair operation may have been triggered by a node\n+% that was out of sync with the local node. Thus, any time\n+% we receive a read repair request we need to check if we\n+% may have recently purged any of the given revisions and\n+% ignore them if so.\n+%\n+% This is accomplished by looking at the purge infos that we\n+% have locally that have not been replicated to the remote\n+% node. The logic here is that we may have received the purge\n+% request before the remote shard copy. So to check that we\n+% need to look at the purge infos that we have locally but\n+% have not yet sent to the remote copy.\n+%\n+% NodeRevs is a list of the {node(), [rev()]} tuples passed\n+% as the read_repair option to update_docs.\n+read_repair_filter(Db, Docs, NodeRevs) ->\n+    [#doc{id = DocId} | _] = Docs,\n+    Nodes = lists:usort([Node || {Node, _} <- NodeRevs, Node /= node()]),\n+    NodeSeqs = get_node_seqs(Db, Nodes),\n+\n+    {ok, DbPSeq} = couch_db:get_purge_seq(Db),\n+    Lag = config:get_integer(\"couchdb\", \"read_repair_lag\", 100),\n+\n+    % Filter out read-repair updates from any node that is\n+    % so out of date that it would force us to scan a large\n+    % number of purge infos\n+    NodeFiltFun = fun({Node, _Revs}) ->\n+        {Node, NodeSeq} = lists:keyfind(Node, 1, NodeSeqs),\n+        NodeSeq >= DbPSeq - Lag\n+    end,\n+    RecentNodeRevs = lists:filter(NodeFiltFun, NodeRevs),\n+\n+    % For each node we scan the purge infos to filter out any\n+    % revisions that have been locally purged since we last\n+    % replicated to the remote node's shard copy.\n+    AllowableRevs = lists:foldl(fun({Node, Revs}, RevAcc) ->\n+        {Node, StartSeq} = lists:keyfind(Node, 1, NodeSeqs),\n+        FoldFun = fun({_PSeq, _UUID, PDocId, PRevs}, InnerAcc) ->\n+            if PDocId /= DocId -> {ok, InnerAcc}; true ->\n+                {ok, InnerAcc -- PRevs}\n+            end\n+        end,\n+        {ok, FiltRevs} = couch_db:fold_purge_infos(Db, StartSeq, FoldFun, Revs),\n+        lists:usort(FiltRevs ++ RevAcc)\n+    end, [], RecentNodeRevs),\n+\n+    % Finally, filter the doc updates to only include revisions\n+    % that have not been purged locally.\n+    DocFiltFun = fun(#doc{revs = {Pos, [Rev | _]}}) ->\n+        lists:member({Pos, Rev}, AllowableRevs)\n+    end,\n+    lists:filter(DocFiltFun, Docs).\n+\n+\n+get_node_seqs(Db, Nodes) ->\n+    % Gather the list of {Node, PurgeSeq} pairs for all nodes\n+    % that are present in our read repair group\n+    FoldFun = fun(#doc{id = Id, body = {Props}}, Acc) ->\n+        case Id of\n+            <<?LOCAL_DOC_PREFIX, \"purge-mem3-\", _/binary>> ->\n+                TgtNode = couch_util:get_value(<<\"target_node\">>, Props),\n+                PurgeSeq = couch_util:get_value(<<\"purge_seq\">>, Props),\n+                case lists:keyfind(TgtNode, 1, Acc) of\n+                    {_, OldSeq} ->\n+                        NewSeq = erlang:max(OldSeq, PurgeSeq),\n+                        NewEntry = {TgtNode, NewSeq},\n+                        NewAcc = lists:keyreplace(TgtNode, 1, Acc, NewEntry),\n+                        {ok, NewAcc};\n+                    false ->\n+                        {ok, Acc}\n+                end;\n+            _ ->\n+                % We've processed all _local mem3 purge docs\n+                {stop, Acc}\n+        end\n+    end,\n+    InitAcc = [{list_to_binary(atom_to_list(Node)), 0} || Node <- Nodes],\n+    Opts = [{start_key, <<?LOCAL_DOC_PREFIX, \"/purge-mem3-\">>}],","path":"src/fabric/src/fabric_rpc.erl","position":null,"original_position":148,"commit_id":"404ce545ac6e58456921aefb30764f5b4d993f85","original_commit_id":"b719f84e9bd9a7d330dac0f3a8dd7545ec4c9f9a","user":{"login":"jiangphcn","id":18000622,"node_id":"MDQ6VXNlcjE4MDAwNjIy","avatar_url":"https://avatars3.githubusercontent.com/u/18000622?v=4","gravatar_id":"","url":"https://api.github.com/users/jiangphcn","html_url":"https://github.com/jiangphcn","followers_url":"https://api.github.com/users/jiangphcn/followers","following_url":"https://api.github.com/users/jiangphcn/following{/other_user}","gists_url":"https://api.github.com/users/jiangphcn/gists{/gist_id}","starred_url":"https://api.github.com/users/jiangphcn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jiangphcn/subscriptions","organizations_url":"https://api.github.com/users/jiangphcn/orgs","repos_url":"https://api.github.com/users/jiangphcn/repos","events_url":"https://api.github.com/users/jiangphcn/events{/privacy}","received_events_url":"https://api.github.com/users/jiangphcn/received_events","type":"User","site_admin":false},"body":"Good catch, and fixed in 404ce54 ","created_at":"2018-06-14T01:45:04Z","updated_at":"2018-06-14T01:45:04Z","html_url":"https://github.com/apache/couchdb/pull/1370#discussion_r195283123","pull_request_url":"https://api.github.com/repos/apache/couchdb/pulls/1370","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/apache/couchdb/pulls/comments/195283123"},"html":{"href":"https://github.com/apache/couchdb/pull/1370#discussion_r195283123"},"pull_request":{"href":"https://api.github.com/repos/apache/couchdb/pulls/1370"}},"in_reply_to_id":195273528},"pull_request":{"url":"https://api.github.com/repos/apache/couchdb/pulls/1370","id":192099831,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkyMDk5ODMx","html_url":"https://github.com/apache/couchdb/pull/1370","diff_url":"https://github.com/apache/couchdb/pull/1370.diff","patch_url":"https://github.com/apache/couchdb/pull/1370.patch","issue_url":"https://api.github.com/repos/apache/couchdb/issues/1370","number":1370,"state":"open","locked":false,"title":"[5/5] Clustered Purge Implementation","user":{"login":"davisp","id":19929,"node_id":"MDQ6VXNlcjE5OTI5","avatar_url":"https://avatars3.githubusercontent.com/u/19929?v=4","gravatar_id":"","url":"https://api.github.com/users/davisp","html_url":"https://github.com/davisp","followers_url":"https://api.github.com/users/davisp/followers","following_url":"https://api.github.com/users/davisp/following{/other_user}","gists_url":"https://api.github.com/users/davisp/gists{/gist_id}","starred_url":"https://api.github.com/users/davisp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davisp/subscriptions","organizations_url":"https://api.github.com/users/davisp/orgs","repos_url":"https://api.github.com/users/davisp/repos","events_url":"https://api.github.com/users/davisp/events{/privacy}","received_events_url":"https://api.github.com/users/davisp/received_events","type":"User","site_admin":false},"body":"## Overview\r\n\r\nThis PR implements clustered purge. Its big.\r\n\r\nThere are roughly five large chunks for clustered purge:\r\n\r\n1. Single shard APIs\r\n2. Updates to couch_mrview\r\n3. Internal replication\r\n4. Read-repair\r\n5. Clustered API\r\n\r\nAt the shard level the major changes are to add two new indexes for purge requests. These indexes store the history of purge requests to a shard (rather than the old method of just storing the most recent purge). This allows for secondary indices and internal replication to manage their eventual consistency. This is the bulk of the PR in that its adding both the implementation and a whole bunch of tests for clustered purge.\r\n\r\nOne note on naming internally and in commit notes is that a \"purge request\" is what's sent in a single HTTP request to the purge end point. A \"purge info\" is a single `{DocId, Revs}` entry. The new indexes in the shard deal with purge infos as they lose any notion of bundling from which request they came in after they're stored.\r\n\r\nThe changes to couch_mrview are fairly straightforward after the single node API changes. The only thing that will be interesting in this commit is how we use a _local doc to track where the secondary index has processed in the purge sequence. This is necessary so that compaction knows when it can discard purge infos.\r\n\r\nInternal replication is fairly straightforward. This update just ensures that we synchronize our purge infos between each shard so that we don't inadvertently undo a purge request when synchronizing shards.\r\n\r\nRead-repair is somewhat tricky. The thing to note here is that when we open a document we track which revisions came from which nodes. Then if read-repair is required we pass that information along with the update request. This way a node can filter out requests from any node that is either a) not up to date with its synchronization or b) we have explicitly purged a revision that has not been sent to the node from whence the revision came back. That last bit of logic may sound kind of odd but the thing to remember is that we could completely remove a revision from a cluster and then re-introduce it later on. This means that we have to reject re-application of a revision for a closed period of time (rather than rejecting it forever).\r\n\r\nThe clustered API is rather straightforward for anyone familiar any of the existing fabric coordinator and HTTPD handler code.\r\n\r\n## Testing recommendations\r\n\r\n`make check`\r\n\r\nClustered purge comes with some fairly extensive testing though I'm very much open for suggestions on new tests.\r\n\r\n## Related Issues or Pull Requests\r\n\r\nThis PR depends on:\r\n\r\n#1366 \r\n#1367 \r\n#1368 \r\n#1369\r\n\r\n## Checklist\r\n\r\n- [x] Code is written and works correctly (hopefully ;)\r\n- [x] Changes are covered by tests;\r\n- [ ] Documentation reflects the changes;\r\n\r\nFor docs this doesn't change the existing purge APIs but I will need to open a PR against the docs to write up some of the caveats and footgun warnings that we want to add for this.","created_at":"2018-06-01T17:44:02Z","updated_at":"2018-06-14T01:45:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0ce007956a8c5f5f163e67191decaa5a8e0410f0","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/couchdb/pulls/1370/commits","review_comments_url":"https://api.github.com/repos/apache/couchdb/pulls/1370/comments","review_comment_url":"https://api.github.com/repos/apache/couchdb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/couchdb/issues/1370/comments","statuses_url":"https://api.github.com/repos/apache/couchdb/statuses/404ce545ac6e58456921aefb30764f5b4d993f85","head":{"label":"apache:COUCHDB-3326-clustered-purge-pr5-implementation","ref":"COUCHDB-3326-clustered-purge-pr5-implementation","sha":"404ce545ac6e58456921aefb30764f5b4d993f85","user":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":206417,"node_id":"MDEwOlJlcG9zaXRvcnkyMDY0MTc=","name":"couchdb","full_name":"apache/couchdb","owner":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/couchdb","description":"Apache CouchDB","fork":false,"url":"https://api.github.com/repos/apache/couchdb","forks_url":"https://api.github.com/repos/apache/couchdb/forks","keys_url":"https://api.github.com/repos/apache/couchdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/couchdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/couchdb/teams","hooks_url":"https://api.github.com/repos/apache/couchdb/hooks","issue_events_url":"https://api.github.com/repos/apache/couchdb/issues/events{/number}","events_url":"https://api.github.com/repos/apache/couchdb/events","assignees_url":"https://api.github.com/repos/apache/couchdb/assignees{/user}","branches_url":"https://api.github.com/repos/apache/couchdb/branches{/branch}","tags_url":"https://api.github.com/repos/apache/couchdb/tags","blobs_url":"https://api.github.com/repos/apache/couchdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/couchdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/couchdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/couchdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/couchdb/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/couchdb/languages","stargazers_url":"https://api.github.com/repos/apache/couchdb/stargazers","contributors_url":"https://api.github.com/repos/apache/couchdb/contributors","subscribers_url":"https://api.github.com/repos/apache/couchdb/subscribers","subscription_url":"https://api.github.com/repos/apache/couchdb/subscription","commits_url":"https://api.github.com/repos/apache/couchdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/couchdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/couchdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/couchdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/couchdb/contents/{+path}","compare_url":"https://api.github.com/repos/apache/couchdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/couchdb/merges","archive_url":"https://api.github.com/repos/apache/couchdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/couchdb/downloads","issues_url":"https://api.github.com/repos/apache/couchdb/issues{/number}","pulls_url":"https://api.github.com/repos/apache/couchdb/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/couchdb/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/couchdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/couchdb/labels{/name}","releases_url":"https://api.github.com/repos/apache/couchdb/releases{/id}","deployments_url":"https://api.github.com/repos/apache/couchdb/deployments","created_at":"2009-05-21T02:03:38Z","updated_at":"2018-06-13T22:53:20Z","pushed_at":"2018-06-14T01:44:02Z","git_url":"git://github.com/apache/couchdb.git","ssh_url":"git@github.com:apache/couchdb.git","clone_url":"https://github.com/apache/couchdb.git","svn_url":"https://github.com/apache/couchdb","homepage":"","size":28260,"stargazers_count":3682,"watchers_count":3682,"language":"Erlang","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":779,"mirror_url":null,"archived":false,"open_issues_count":155,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":779,"open_issues":155,"watchers":3682,"default_branch":"master"}},"base":{"label":"apache:COUCHDB-3326-clustered-purge-pr4-on-compact-plugin","ref":"COUCHDB-3326-clustered-purge-pr4-on-compact-plugin","sha":"b4f3cebe43857d0c5846111c4812c7c0ac7ac802","user":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":206417,"node_id":"MDEwOlJlcG9zaXRvcnkyMDY0MTc=","name":"couchdb","full_name":"apache/couchdb","owner":{"login":"apache","id":47359,"node_id":"MDEyOk9yZ2FuaXphdGlvbjQ3MzU5","avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/couchdb","description":"Apache CouchDB","fork":false,"url":"https://api.github.com/repos/apache/couchdb","forks_url":"https://api.github.com/repos/apache/couchdb/forks","keys_url":"https://api.github.com/repos/apache/couchdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/couchdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/couchdb/teams","hooks_url":"https://api.github.com/repos/apache/couchdb/hooks","issue_events_url":"https://api.github.com/repos/apache/couchdb/issues/events{/number}","events_url":"https://api.github.com/repos/apache/couchdb/events","assignees_url":"https://api.github.com/repos/apache/couchdb/assignees{/user}","branches_url":"https://api.github.com/repos/apache/couchdb/branches{/branch}","tags_url":"https://api.github.com/repos/apache/couchdb/tags","blobs_url":"https://api.github.com/repos/apache/couchdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/couchdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/couchdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/couchdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/couchdb/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/couchdb/languages","stargazers_url":"https://api.github.com/repos/apache/couchdb/stargazers","contributors_url":"https://api.github.com/repos/apache/couchdb/contributors","subscribers_url":"https://api.github.com/repos/apache/couchdb/subscribers","subscription_url":"https://api.github.com/repos/apache/couchdb/subscription","commits_url":"https://api.github.com/repos/apache/couchdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/couchdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/couchdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/couchdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/couchdb/contents/{+path}","compare_url":"https://api.github.com/repos/apache/couchdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/couchdb/merges","archive_url":"https://api.github.com/repos/apache/couchdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/couchdb/downloads","issues_url":"https://api.github.com/repos/apache/couchdb/issues{/number}","pulls_url":"https://api.github.com/repos/apache/couchdb/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/couchdb/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/couchdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/couchdb/labels{/name}","releases_url":"https://api.github.com/repos/apache/couchdb/releases{/id}","deployments_url":"https://api.github.com/repos/apache/couchdb/deployments","created_at":"2009-05-21T02:03:38Z","updated_at":"2018-06-13T22:53:20Z","pushed_at":"2018-06-14T01:44:02Z","git_url":"git://github.com/apache/couchdb.git","ssh_url":"git@github.com:apache/couchdb.git","clone_url":"https://github.com/apache/couchdb.git","svn_url":"https://github.com/apache/couchdb","homepage":"","size":28260,"stargazers_count":3682,"watchers_count":3682,"language":"Erlang","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":779,"mirror_url":null,"archived":false,"open_issues_count":155,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":779,"open_issues":155,"watchers":3682,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/couchdb/pulls/1370"},"html":{"href":"https://github.com/apache/couchdb/pull/1370"},"issue":{"href":"https://api.github.com/repos/apache/couchdb/issues/1370"},"comments":{"href":"https://api.github.com/repos/apache/couchdb/issues/1370/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/couchdb/pulls/1370/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/couchdb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/couchdb/pulls/1370/commits"},"statuses":{"href":"https://api.github.com/repos/apache/couchdb/statuses/404ce545ac6e58456921aefb30764f5b4d993f85"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"jiangphcn"}}