{"action":"created","comment":{"url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments/97966554","pull_request_review_id":18592228,"id":97966554,"diff_hunk":"@@ -0,0 +1,240 @@\n+// Copyright 2016 The go-ethereum Authors\n+// This file is part of the go-ethereum library.\n+//\n+// The go-ethereum library is free software: you can redistribute it and/or modify\n+// it under the terms of the GNU Lesser General Public License as published by\n+// the Free Software Foundation, either version 3 of the License, or\n+// (at your option) any later version.\n+//\n+// The go-ethereum library is distributed in the hope that it will be useful,\n+// but WITHOUT ANY WARRANTY; without even the implied warranty of\n+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+// GNU Lesser General Public License for more details.\n+//\n+// You should have received a copy of the GNU Lesser General Public License\n+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.\n+\n+package event\n+\n+import (\n+\t\"errors\"\n+\t\"reflect\"\n+\t\"sync\"\n+)\n+\n+var errBadChannel = errors.New(\"event: Subscribe argument does not have sendable channel type\")\n+\n+// Feed implements one-to-many subscriptions where the carrier of events is a channel.\n+// Values sent to a Feed are delivered to all subscribed channels simultaneously.\n+//\n+// Feeds can only be used with a single type. The type is determined by the first Send or\n+// Subscribe operation. Subsequent calls to these methods panic if the type does not\n+// match.\n+//\n+// The zero value is ready to use.\n+type Feed struct {\n+\tsendLock  chan struct{}    // one-element buffer, empty when held\n+\tremoveSub chan interface{} // interrupts Send\n+\tsendCases caseList         // the active set of select cases used by Send\n+\n+\t// The inbox holds newly subscribed channels until they are added to sendCases.\n+\tmu     sync.Mutex\n+\tinbox  caseList\n+\tetype  reflect.Type\n+\tclosed bool\n+}\n+\n+type feedTypeError struct {\n+\tgot, want reflect.Type\n+\top        string\n+}\n+\n+func (e feedTypeError) Error() string {\n+\treturn \"event: wrong type in \" + e.op + \" got \" + e.got.String() + \", want \" + e.want.String()\n+}\n+\n+func (f *Feed) init() {\n+\tif f.sendLock != nil {\n+\t\treturn\n+\t}\n+\tf.removeSub = make(chan interface{})\n+\tf.sendLock = make(chan struct{}, 1)\n+\tf.sendLock <- struct{}{}\n+\tf.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}}\n+}\n+\n+// Subscribe adds a channel to the feed. Future sends will be delivered on the channel\n+// until the subscription is canceled. All channels added must have the same element type.\n+//\n+// The channel should have ample buffer space to avoid blocking other subscribers.\n+func (f *Feed) Subscribe(channel interface{}) Subscription {\n+\tchanval := reflect.ValueOf(channel)\n+\tchantyp := chanval.Type()\n+\tif chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 {\n+\t\tpanic(errBadChannel)\n+\t}\n+\tsub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)}\n+\n+\tf.mu.Lock()\n+\tdefer f.mu.Unlock()\n+\tf.init()\n+\tif !f.typecheck(chantyp.Elem()) {\n+\t\tpanic(feedTypeError{op: \"Subscribe\", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)})\n+\t}\n+\t// Add the select case to the inbox.\n+\t// The next Send will add it to f.sendCases.\n+\tcas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval}\n+\tf.inbox = append(f.inbox, cas)\n+\treturn sub\n+}\n+\n+// note: callers must hold f.mu\n+func (f *Feed) typecheck(typ reflect.Type) bool {\n+\tif f.etype == nil {\n+\t\tf.etype = typ\n+\t\treturn true\n+\t}\n+\treturn f.etype == typ\n+}\n+\n+func (f *Feed) remove(sub *feedSub) {\n+\t// Delete from inbox first, which covers channels\n+\t// that have not been added to f.sendCases yet.\n+\tch := sub.channel.Interface()\n+\tf.mu.Lock()\n+\tindex := f.inbox.find(ch)\n+\tif index != -1 {\n+\t\tf.inbox = f.inbox.delete(index)\n+\t\tf.mu.Unlock()\n+\t\treturn\n+\t}\n+\tf.mu.Unlock()\n+\n+\tselect {\n+\tcase f.removeSub <- ch:\n+\t\t// Send will remove the channel from f.sendCases.\n+\tcase <-f.sendLock:\n+\t\t// No Send is in progress, delete the channel now that we have the send lock.\n+\t\tf.sendCases = f.sendCases.delete(f.sendCases.find(ch))\n+\t\tf.sendLock <- struct{}{}\n+\t}\n+}\n+\n+// Send delivers to all subscribed channels simultaneously.\n+// It returns the number of subscribers that the value was sent to.\n+func (f *Feed) Send(value interface{}) (nsent int) {\n+\tf.mu.Lock()\n+\tf.init()\n+\t<-f.sendLock\n+\t// Add new subscriptions from the inbox, then clear it.\n+\tf.sendCases = append(f.sendCases, f.inbox...)\n+\tfor i := range f.inbox {\n+\t\tf.inbox[i] = reflect.SelectCase{}\n+\t}\n+\tf.inbox = f.inbox[:0]","path":"event/feed.go","position":134,"original_position":134,"commit_id":"a2b4abd89adf0404b43fcd19766bac37009032a5","original_commit_id":"6d5e100d0dc6fc0b905610850a75b5d4fa907739","user":{"login":"fjl","id":6915,"avatar_url":"https://avatars.githubusercontent.com/u/6915?v=3","gravatar_id":"","url":"https://api.github.com/users/fjl","html_url":"https://github.com/fjl","followers_url":"https://api.github.com/users/fjl/followers","following_url":"https://api.github.com/users/fjl/following{/other_user}","gists_url":"https://api.github.com/users/fjl/gists{/gist_id}","starred_url":"https://api.github.com/users/fjl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fjl/subscriptions","organizations_url":"https://api.github.com/users/fjl/orgs","repos_url":"https://api.github.com/users/fjl/repos","events_url":"https://api.github.com/users/fjl/events{/privacy}","received_events_url":"https://api.github.com/users/fjl/received_events","type":"User","site_admin":false},"body":"It resets them just before this line.","created_at":"2017-01-26T10:31:43Z","updated_at":"2017-01-26T10:31:43Z","html_url":"https://github.com/ethereum/go-ethereum/pull/3605#discussion_r97966554","pull_request_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605","_links":{"self":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments/97966554"},"html":{"href":"https://github.com/ethereum/go-ethereum/pull/3605#discussion_r97966554"},"pull_request":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605"}}},"pull_request":{"url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605","id":103140766,"html_url":"https://github.com/ethereum/go-ethereum/pull/3605","diff_url":"https://github.com/ethereum/go-ethereum/pull/3605.diff","patch_url":"https://github.com/ethereum/go-ethereum/pull/3605.patch","issue_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/3605","number":3605,"state":"open","locked":false,"title":"event: add new Subscription type and related utilities","user":{"login":"fjl","id":6915,"avatar_url":"https://avatars.githubusercontent.com/u/6915?v=3","gravatar_id":"","url":"https://api.github.com/users/fjl","html_url":"https://github.com/fjl","followers_url":"https://api.github.com/users/fjl/followers","following_url":"https://api.github.com/users/fjl/following{/other_user}","gists_url":"https://api.github.com/users/fjl/gists{/gist_id}","starred_url":"https://api.github.com/users/fjl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fjl/subscriptions","organizations_url":"https://api.github.com/users/fjl/orgs","repos_url":"https://api.github.com/users/fjl/repos","events_url":"https://api.github.com/users/fjl/events{/privacy}","received_events_url":"https://api.github.com/users/fjl/received_events","type":"User","site_admin":false},"body":"This PR introduces a new Subscription type, which is synonymous with\r\nethereum.Subscription. It also adds a couple of utilities that make\r\nworking with Subscriptions easier. The most complex utility is Feed, a\r\nsynchronisation device that implements broadcast subscriptions. Feed is\r\nslightly faster than TypeMux and will replace uses of TypeMux across the\r\ngo-ethereum codebase in the future.\r\n\r\nCloses #1867","created_at":"2017-01-25T15:27:21Z","updated_at":"2017-01-26T10:31:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"224e2ad782108f272caa62711464071a395fe6ec","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605/commits","review_comments_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605/comments","review_comment_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/3605/comments","statuses_url":"https://api.github.com/repos/ethereum/go-ethereum/statuses/a2b4abd89adf0404b43fcd19766bac37009032a5","head":{"label":"fjl:event-feed","ref":"event-feed","sha":"a2b4abd89adf0404b43fcd19766bac37009032a5","user":{"login":"fjl","id":6915,"avatar_url":"https://avatars.githubusercontent.com/u/6915?v=3","gravatar_id":"","url":"https://api.github.com/users/fjl","html_url":"https://github.com/fjl","followers_url":"https://api.github.com/users/fjl/followers","following_url":"https://api.github.com/users/fjl/following{/other_user}","gists_url":"https://api.github.com/users/fjl/gists{/gist_id}","starred_url":"https://api.github.com/users/fjl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fjl/subscriptions","organizations_url":"https://api.github.com/users/fjl/orgs","repos_url":"https://api.github.com/users/fjl/repos","events_url":"https://api.github.com/users/fjl/events{/privacy}","received_events_url":"https://api.github.com/users/fjl/received_events","type":"User","site_admin":false},"repo":{"id":24951427,"name":"go-ethereum","full_name":"fjl/go-ethereum","owner":{"login":"fjl","id":6915,"avatar_url":"https://avatars.githubusercontent.com/u/6915?v=3","gravatar_id":"","url":"https://api.github.com/users/fjl","html_url":"https://github.com/fjl","followers_url":"https://api.github.com/users/fjl/followers","following_url":"https://api.github.com/users/fjl/following{/other_user}","gists_url":"https://api.github.com/users/fjl/gists{/gist_id}","starred_url":"https://api.github.com/users/fjl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fjl/subscriptions","organizations_url":"https://api.github.com/users/fjl/orgs","repos_url":"https://api.github.com/users/fjl/repos","events_url":"https://api.github.com/users/fjl/events{/privacy}","received_events_url":"https://api.github.com/users/fjl/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/fjl/go-ethereum","description":"Work fork of go-ethereum.","fork":true,"url":"https://api.github.com/repos/fjl/go-ethereum","forks_url":"https://api.github.com/repos/fjl/go-ethereum/forks","keys_url":"https://api.github.com/repos/fjl/go-ethereum/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fjl/go-ethereum/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fjl/go-ethereum/teams","hooks_url":"https://api.github.com/repos/fjl/go-ethereum/hooks","issue_events_url":"https://api.github.com/repos/fjl/go-ethereum/issues/events{/number}","events_url":"https://api.github.com/repos/fjl/go-ethereum/events","assignees_url":"https://api.github.com/repos/fjl/go-ethereum/assignees{/user}","branches_url":"https://api.github.com/repos/fjl/go-ethereum/branches{/branch}","tags_url":"https://api.github.com/repos/fjl/go-ethereum/tags","blobs_url":"https://api.github.com/repos/fjl/go-ethereum/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fjl/go-ethereum/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fjl/go-ethereum/git/refs{/sha}","trees_url":"https://api.github.com/repos/fjl/go-ethereum/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fjl/go-ethereum/statuses/{sha}","languages_url":"https://api.github.com/repos/fjl/go-ethereum/languages","stargazers_url":"https://api.github.com/repos/fjl/go-ethereum/stargazers","contributors_url":"https://api.github.com/repos/fjl/go-ethereum/contributors","subscribers_url":"https://api.github.com/repos/fjl/go-ethereum/subscribers","subscription_url":"https://api.github.com/repos/fjl/go-ethereum/subscription","commits_url":"https://api.github.com/repos/fjl/go-ethereum/commits{/sha}","git_commits_url":"https://api.github.com/repos/fjl/go-ethereum/git/commits{/sha}","comments_url":"https://api.github.com/repos/fjl/go-ethereum/comments{/number}","issue_comment_url":"https://api.github.com/repos/fjl/go-ethereum/issues/comments{/number}","contents_url":"https://api.github.com/repos/fjl/go-ethereum/contents/{+path}","compare_url":"https://api.github.com/repos/fjl/go-ethereum/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fjl/go-ethereum/merges","archive_url":"https://api.github.com/repos/fjl/go-ethereum/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fjl/go-ethereum/downloads","issues_url":"https://api.github.com/repos/fjl/go-ethereum/issues{/number}","pulls_url":"https://api.github.com/repos/fjl/go-ethereum/pulls{/number}","milestones_url":"https://api.github.com/repos/fjl/go-ethereum/milestones{/number}","notifications_url":"https://api.github.com/repos/fjl/go-ethereum/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fjl/go-ethereum/labels{/name}","releases_url":"https://api.github.com/repos/fjl/go-ethereum/releases{/id}","deployments_url":"https://api.github.com/repos/fjl/go-ethereum/deployments","created_at":"2014-10-08T17:12:04Z","updated_at":"2015-05-29T23:48:03Z","pushed_at":"2017-01-25T17:44:28Z","git_url":"git://github.com/fjl/go-ethereum.git","ssh_url":"git@github.com:fjl/go-ethereum.git","clone_url":"https://github.com/fjl/go-ethereum.git","svn_url":"https://github.com/fjl/go-ethereum","homepage":"","size":76083,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ethereum:master","ref":"master","sha":"1886d03faa9b7d8cdf335da84c297d30c213bb69","user":{"login":"ethereum","id":6250754,"avatar_url":"https://avatars.githubusercontent.com/u/6250754?v=3","gravatar_id":"","url":"https://api.github.com/users/ethereum","html_url":"https://github.com/ethereum","followers_url":"https://api.github.com/users/ethereum/followers","following_url":"https://api.github.com/users/ethereum/following{/other_user}","gists_url":"https://api.github.com/users/ethereum/gists{/gist_id}","starred_url":"https://api.github.com/users/ethereum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ethereum/subscriptions","organizations_url":"https://api.github.com/users/ethereum/orgs","repos_url":"https://api.github.com/users/ethereum/repos","events_url":"https://api.github.com/users/ethereum/events{/privacy}","received_events_url":"https://api.github.com/users/ethereum/received_events","type":"Organization","site_admin":false},"repo":{"id":15452919,"name":"go-ethereum","full_name":"ethereum/go-ethereum","owner":{"login":"ethereum","id":6250754,"avatar_url":"https://avatars.githubusercontent.com/u/6250754?v=3","gravatar_id":"","url":"https://api.github.com/users/ethereum","html_url":"https://github.com/ethereum","followers_url":"https://api.github.com/users/ethereum/followers","following_url":"https://api.github.com/users/ethereum/following{/other_user}","gists_url":"https://api.github.com/users/ethereum/gists{/gist_id}","starred_url":"https://api.github.com/users/ethereum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ethereum/subscriptions","organizations_url":"https://api.github.com/users/ethereum/orgs","repos_url":"https://api.github.com/users/ethereum/repos","events_url":"https://api.github.com/users/ethereum/events{/privacy}","received_events_url":"https://api.github.com/users/ethereum/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ethereum/go-ethereum","description":"Official Go implementation of the Ethereum protocol","fork":false,"url":"https://api.github.com/repos/ethereum/go-ethereum","forks_url":"https://api.github.com/repos/ethereum/go-ethereum/forks","keys_url":"https://api.github.com/repos/ethereum/go-ethereum/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ethereum/go-ethereum/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ethereum/go-ethereum/teams","hooks_url":"https://api.github.com/repos/ethereum/go-ethereum/hooks","issue_events_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/events{/number}","events_url":"https://api.github.com/repos/ethereum/go-ethereum/events","assignees_url":"https://api.github.com/repos/ethereum/go-ethereum/assignees{/user}","branches_url":"https://api.github.com/repos/ethereum/go-ethereum/branches{/branch}","tags_url":"https://api.github.com/repos/ethereum/go-ethereum/tags","blobs_url":"https://api.github.com/repos/ethereum/go-ethereum/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ethereum/go-ethereum/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ethereum/go-ethereum/git/refs{/sha}","trees_url":"https://api.github.com/repos/ethereum/go-ethereum/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ethereum/go-ethereum/statuses/{sha}","languages_url":"https://api.github.com/repos/ethereum/go-ethereum/languages","stargazers_url":"https://api.github.com/repos/ethereum/go-ethereum/stargazers","contributors_url":"https://api.github.com/repos/ethereum/go-ethereum/contributors","subscribers_url":"https://api.github.com/repos/ethereum/go-ethereum/subscribers","subscription_url":"https://api.github.com/repos/ethereum/go-ethereum/subscription","commits_url":"https://api.github.com/repos/ethereum/go-ethereum/commits{/sha}","git_commits_url":"https://api.github.com/repos/ethereum/go-ethereum/git/commits{/sha}","comments_url":"https://api.github.com/repos/ethereum/go-ethereum/comments{/number}","issue_comment_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/comments{/number}","contents_url":"https://api.github.com/repos/ethereum/go-ethereum/contents/{+path}","compare_url":"https://api.github.com/repos/ethereum/go-ethereum/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ethereum/go-ethereum/merges","archive_url":"https://api.github.com/repos/ethereum/go-ethereum/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ethereum/go-ethereum/downloads","issues_url":"https://api.github.com/repos/ethereum/go-ethereum/issues{/number}","pulls_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls{/number}","milestones_url":"https://api.github.com/repos/ethereum/go-ethereum/milestones{/number}","notifications_url":"https://api.github.com/repos/ethereum/go-ethereum/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ethereum/go-ethereum/labels{/name}","releases_url":"https://api.github.com/repos/ethereum/go-ethereum/releases{/id}","deployments_url":"https://api.github.com/repos/ethereum/go-ethereum/deployments","created_at":"2013-12-26T13:05:46Z","updated_at":"2017-01-26T02:31:41Z","pushed_at":"2017-01-26T03:24:13Z","git_url":"git://github.com/ethereum/go-ethereum.git","ssh_url":"git@github.com:ethereum/go-ethereum.git","clone_url":"https://github.com/ethereum/go-ethereum.git","svn_url":"https://github.com/ethereum/go-ethereum","homepage":"https://geth.ethereum.org","size":81418,"stargazers_count":2827,"watchers_count":2827,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":995,"mirror_url":null,"open_issues_count":325,"forks":995,"open_issues":325,"watchers":2827,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605"},"html":{"href":"https://github.com/ethereum/go-ethereum/pull/3605"},"issue":{"href":"https://api.github.com/repos/ethereum/go-ethereum/issues/3605"},"comments":{"href":"https://api.github.com/repos/ethereum/go-ethereum/issues/3605/comments"},"review_comments":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605/comments"},"review_comment":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/3605/commits"},"statuses":{"href":"https://api.github.com/repos/ethereum/go-ethereum/statuses/a2b4abd89adf0404b43fcd19766bac37009032a5"}}}}
{"actor":{"display_login":"fjl"}}