Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pd-client: no need to watch leader #327

Merged
merged 7 commits into from
Sep 22, 2016

Conversation

huachaohuang
Copy link
Contributor

@huachaohuang huachaohuang commented Sep 19, 2016

Since PD server can proxy requests to the leader,
PD client don't need to watch the leader any more.

Now PD client first try to connect to the leader,
if it fails, it will connect to any other PD servers temporarily,
and retry to connect to the leader later.

Update:
When we can't connect to the leader, we will connect to any
other servers temporarily. Meanwhile, we delegate a
goroutine to keep trying to connect to the leader. Once the
delegated goroutine connected to the leader, it sends the
connection to the channel, and we can use the leader
connection to replace the old one.

Reference Issues: #293

Since PD server can proxy requests to the leader,
PD client don't need to watch the leader any more.

Now PD client first try to connect to the leader,
if it fails, it will connect to any other PD servers temporarily,
and retry to connect to the leader later.

Reference Issues: #293
"github.com/pingcap/pd/pkg/rpcutil"
)

func MustRPCCall(c *C, conn net.Conn, request *pdpb.Request) *pdpb.Response {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add comment here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not very meaningful to add comment for these test wrappers, and I have filtered out testutil from golint.

@@ -55,7 +61,7 @@ endif
mv vendor _vendor/vendor

clean:
# clean unix socket
# clean unix socket
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alignment

case <-w.quit:
return
// Add default schema "http://" to addrs.
urls := make([]string, 0, len(w.addrs))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract these to a function


// We can't connect to the leader now, try to reconnect later.
if !isLeader {
time.AfterFunc(reconnectPDTimeout, func() { conn.Close() })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seem that we may meet data race here for connection.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using a channel here, and handling this in the following select.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, for reconnect, I think we can first try to connect leader, if success, then we can close origin connection and use the leader connection

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The document says that "Multiple goroutines may invoke methods on a Conn simultaneously".

I actually create another goroutine to retry to connect to the leader in the first implementation, but that seems a bit complicated. Maybe I should try to simplify that.

When we can't connect to the leader, we will connect to any
other servers temporarily. Meanwhile, we delegate a
goroutine to keep trying to connect to the leader. Once the
delegated goroutine connected to the leader, it sends the
connection to the channel, and we can use the leader
connection to replace the old one.
net.Conn
wg sync.WaitGroup
quit chan struct{}
C chan *conn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C is a little short.


func (c *conn) Close() {
c.Conn.Close()
close(c.quit)
Copy link
Contributor

@qiuyesuifeng qiuyesuifeng Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any risk of panic if we use c.Conn in goroutine loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it, which goroutine loop?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only want to make sure if we close conn first, then close quit channel. Is it OK for us to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The c.quit has nothing to do with the c.Conn, just to notify the connectLeader goroutine to quit, seems safe to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

if err == nil {
c := newConn(conn)
c.wg.Add(1)
go c.connectLeader(urls, reconnectPDTimeout)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we enter here multi times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will enter this only when we connect to other servers first.
The created goroutine will return if it connects to the leader or the original connection is closed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may still meet the leader coroutine doesn't return but current connection breaks and goes to RECONNECT again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's OK, whenever the connection Close(), it will notify the leader goroutine to return.
That's why I wrap the whole thing into a struct.

return &conn{
Conn: c,
quit: make(chan struct{}),
ConnChan: make(chan *conn),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@siddontang
Copy link
Contributor

LGTM

1 similar comment
@qiuyesuifeng
Copy link
Contributor

LGTM

@huachaohuang huachaohuang merged commit 5606df6 into master Sep 22, 2016
@huachaohuang huachaohuang deleted the huachaohuang/pd-client-dont-watch-leader branch September 22, 2016 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants