From e468e72229f597e7e7974350b4419cf248e50d88 Mon Sep 17 00:00:00 2001 From: leventeliu Date: Wed, 29 May 2019 18:07:08 +0800 Subject: [PATCH 1/9] Add counter for session pool and caller --- rpc/mux/pool.go | 23 +++++++++++++++++++++++ rpc/pcaller.go | 27 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/rpc/mux/pool.go b/rpc/mux/pool.go index ef52df35f..40b46feef 100644 --- a/rpc/mux/pool.go +++ b/rpc/mux/pool.go @@ -20,6 +20,7 @@ import ( "net" "strings" "sync" + "sync/atomic" "github.com/pkg/errors" mux "github.com/xtaci/smux" @@ -27,6 +28,13 @@ import ( "github.com/CovenantSQL/CovenantSQL/conf" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/rpc" + "github.com/CovenantSQL/CovenantSQL/utils/log" +) + +var ( + openSession uint32 + openStreamAttempt uint32 + openStreamSucc uint32 ) // Session is the Session type of SessionPool. @@ -91,6 +99,7 @@ func (s *Session) Get() (conn rpc.Client, err error) { if err != nil { return } + atomic.AddUint32(&openSession, 1) s.sess = append(s.sess, sess) s.offset = len(s.sess) - 1 } else { @@ -98,9 +107,11 @@ func (s *Session) Get() (conn rpc.Client, err error) { } // open connection + atomic.AddUint32(&openStreamAttempt, 1) stream, err = sess.OpenStream() if err != nil { // invalidate session + log.WithError(err).Debug("fail to open stream") sessions = nil sessions = append(sessions, s.sess[0:s.offset]...) sessions = append(sessions, s.sess[s.offset+1:]...) @@ -108,10 +119,19 @@ func (s *Session) Get() (conn rpc.Client, err error) { continue } + atomic.AddUint32(&openStreamSucc, 1) return rpc.NewClient(stream), nil } } +func Stat() { + log.WithFields(log.Fields{ + "open_session": openSession, + "open_stream_attempt": openStreamAttempt, + "open_stream_succ": openStreamSucc, + }).Info("session pool stat") +} + // Len returns physical connection count. func (s *Session) Len() int { s.RLock() @@ -203,10 +223,13 @@ func (p *SessionPool) GetEx(id proto.NodeID, isAnonymous bool) (conn rpc.Client, if sess, err = newSession(id, true); err != nil { return } + atomic.AddUint32(&openSession, 1) + atomic.AddUint32(&openStreamAttempt, 1) if stream, err = sess.OpenStream(); err != nil { err = errors.Wrapf(err, "open new session to %s failed", id) return } + atomic.AddUint32(&openStreamSucc, 1) return rpc.NewClient(&oneOffMuxConn{ sess: sess, Stream: stream, diff --git a/rpc/pcaller.go b/rpc/pcaller.go index e89e25638..66b132f64 100644 --- a/rpc/pcaller.go +++ b/rpc/pcaller.go @@ -21,12 +21,19 @@ import ( "net/rpc" "strings" "sync" + "sync/atomic" "time" "github.com/pkg/errors" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" + "github.com/CovenantSQL/CovenantSQL/utils/log" +) + +var ( + dialCount uint32 + closeCount uint32 ) // PersistentCaller is a wrapper for session pooling and RPC calling. @@ -57,11 +64,23 @@ func (c *PersistentCaller) initClient(isAnonymous bool) (err error) { err = errors.Wrap(err, "dial to node failed") return } + log.WithFields(log.Fields{ + "is_anonymous": isAnonymous, + "node": c.TargetID, + }).Info("dial node with pool") + atomic.AddUint32(&dialCount, 1) //c.TargetAddr = conn.RemoteAddr().String() } return } +func Stat() { + log.WithFields(log.Fields{ + "dial_count": dialCount, + "close_count": closeCount, + }).Info("pcaller stat") +} + // Call invokes the named function, waits for it to complete, and returns its error status. func (c *PersistentCaller) Call(method string, args interface{}, reply interface{}) (err error) { startTime := time.Now() @@ -100,6 +119,10 @@ func (c *PersistentCaller) Call(method string, args interface{}, reply interface func (c *PersistentCaller) ResetClient() (err error) { c.Lock() if c.client != nil { + log.WithFields(log.Fields{ + "node": c.TargetID, + }).Info("close node") + atomic.AddUint32(&closeCount, 1) _ = c.client.Close() } c.client = nil @@ -112,6 +135,10 @@ func (c *PersistentCaller) Close() { c.Lock() defer c.Unlock() if c.client != nil { + log.WithFields(log.Fields{ + "node": c.TargetID, + }).Info("close node") + atomic.AddUint32(&closeCount, 1) _ = c.client.Close() } } From 824cfb11cd285742581ec5d507ec434eae7ea7b2 Mon Sep 17 00:00:00 2001 From: leventeliu Date: Wed, 29 May 2019 16:54:33 +0800 Subject: [PATCH 2/9] Add debug info and fix advance payment setting --- cmd/cql-minerd/integration_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/cql-minerd/integration_test.go b/cmd/cql-minerd/integration_test.go index ceb079a8c..008ee9ab8 100644 --- a/cmd/cql-minerd/integration_test.go +++ b/cmd/cql-minerd/integration_test.go @@ -47,6 +47,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/naconn" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" + rrpc "github.com/CovenantSQL/CovenantSQL/rpc" rpc "github.com/CovenantSQL/CovenantSQL/rpc/mux" "github.com/CovenantSQL/CovenantSQL/test" "github.com/CovenantSQL/CovenantSQL/types" @@ -962,7 +963,7 @@ func benchOutsideMinerWithTargetMinerList( Node: minerCount, UseEventualConsistency: benchEventualConsistency, IsolationLevel: int(sql.LevelReadUncommitted), - AdvancePayment: 1000000000, + AdvancePayment: testAdvancePayment, } // wait for chain service var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) @@ -996,6 +997,8 @@ func benchOutsideMinerWithTargetMinerList( So(err, ShouldBeNil) benchDB(b, db, minerCount > 0) + rrpc.Stat() + rpc.Stat() } func BenchmarkClientOnly(b *testing.B) { From ed703428ece8e3232978f726bb7014189ae116ea Mon Sep 17 00:00:00 2001 From: leventeliu Date: Wed, 29 May 2019 21:19:12 +0800 Subject: [PATCH 3/9] Fix mux stream leaking by worker goroutine --- client/conn.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/conn.go b/client/conn.go index 54453e6f8..76be015ef 100644 --- a/client/conn.go +++ b/client/conn.go @@ -54,6 +54,7 @@ type conn struct { // pconn represents a connection to a peer. type pconn struct { + wg *sync.WaitGroup parent *conn ackCh chan *types.Ack pCaller rpc.PCaller @@ -147,8 +148,10 @@ func newConn(cfg *Config) (c *conn, err error) { } func (c *pconn) startAckWorkers(workerCount int) (err error) { + c.wg = &sync.WaitGroup{} c.ackCh = make(chan *types.Ack, workerCount*4) for i := 0; i < workerCount; i++ { + c.wg.Add(1) go c.ackWorker() } return @@ -165,6 +168,8 @@ func (c *pconn) stopAckWorkers() { } func (c *pconn) ackWorker() { + defer c.wg.Done() + var ( oneTime sync.Once pc rpc.PCaller @@ -202,6 +207,7 @@ ackWorkerLoop: func (c *pconn) close() error { c.stopAckWorkers() + c.wg.Wait() if c.pCaller != nil { c.pCaller.Close() } From f0fc722cff721a563875cb461cc83d9ba56e4d8c Mon Sep 17 00:00:00 2001 From: auxten Date: Tue, 28 May 2019 13:42:28 +0800 Subject: [PATCH 4/9] Update README-zh.md --- README-zh.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-zh.md b/README-zh.md index c31cde269..631042f12 100644 --- a/README-zh.md +++ b/README-zh.md @@ -235,6 +235,7 @@ CovenantSQL仍在建设中,测试网已经发布,[尝试一下](https://deve ## 联系我们 +- 添加微信: `CovenantSQL` 加入交流群 - [博客](https://medium.com/@covenant_labs) - [YouTube](https://www.youtube.com/channel/UCe9P_TMiexSHW2GGV5qBmZw) - [邮箱地址](mailto:webmaster@covenantsql.io) @@ -242,5 +243,4 @@ CovenantSQL仍在建设中,测试网已经发布,[尝试一下](https://deve - follow on Twitter - - [![Join the chat at https://gitter.im/CovenantSQL/CovenantSQL](https://badges.gitter.im/CovenantSQL/CovenantSQL.svg)](https://gitter.im/CovenantSQL/CovenantSQL?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From 6543059840fe4ee1adb77b43374274af061cbcd8 Mon Sep 17 00:00:00 2001 From: auxten Date: Tue, 28 May 2019 14:22:09 +0800 Subject: [PATCH 5/9] Add wechat qr code in readme (#351) * Fix typo * Add wechat qr code in readme * Indent QR code * Move to the end --- README-zh.md | 6 +++++- README.md | 4 ++++ logo/wechat.jpeg | Bin 0 -> 39765 bytes xenomint/state.go | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 logo/wechat.jpeg diff --git a/README-zh.md b/README-zh.md index 631042f12..afd8c1cba 100644 --- a/README-zh.md +++ b/README-zh.md @@ -235,7 +235,6 @@ CovenantSQL仍在建设中,测试网已经发布,[尝试一下](https://deve ## 联系我们 -- 添加微信: `CovenantSQL` 加入交流群 - [博客](https://medium.com/@covenant_labs) - [YouTube](https://www.youtube.com/channel/UCe9P_TMiexSHW2GGV5qBmZw) - [邮箱地址](mailto:webmaster@covenantsql.io) @@ -244,3 +243,8 @@ CovenantSQL仍在建设中,测试网已经发布,[尝试一下](https://deve follow on Twitter - [![Join the chat at https://gitter.im/CovenantSQL/CovenantSQL](https://badges.gitter.im/CovenantSQL/CovenantSQL.svg)](https://gitter.im/CovenantSQL/CovenantSQL?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +- 添加微信: `CovenantSQL` 加入交流群 +

+ +

+ diff --git a/README.md b/README.md index 10ff8e234..c6b158ef6 100644 --- a/README.md +++ b/README.md @@ -255,3 +255,7 @@ Storing data on Bitcoin or Ethereum is quite expensive ($4305 / MB on Ethereum 2 - [Forum](https://demo.covenantsql.io/forum/) - follow on Twitter - [![Join the chat at https://gitter.im/CovenantSQL/CovenantSQL](https://badges.gitter.im/CovenantSQL/CovenantSQL.svg)](https://gitter.im/CovenantSQL/CovenantSQL?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +- Add `CovenantSQL` to join WeChat group +

+ +

diff --git a/logo/wechat.jpeg b/logo/wechat.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b715399b7cb4b4659cc4a9741037233e9f6f2632 GIT binary patch literal 39765 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 Date: Tue, 28 May 2019 20:00:27 +0800 Subject: [PATCH 6/9] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c6b158ef6..3c889caf1 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,9 @@ [中文简介](https://github.com/CovenantSQL/CovenantSQL/blob/develop/README-zh.md) -CovenantSQL(CQL) is a Decentralized, GDPR-compliant, Trusted, SQL database with Blockchain features: +CovenantSQL(CQL) is a Byzantine Fault Tolerance relational database built on SQLite: - **ServerLess**: Free, High Availabile, Auto Sync Database Service for Serverless App -- **GDPR-compliant**: Zero pain to be GDPR-compliant. - **SQL**: Most SQL-92 support. - **Decentralize**: Running on Open Internet without Central Coordination. - **Privacy**: Access with Granted Permission and Encryption Pass. From f9577962f28a663f0d955349b02e3ee17ac0caad Mon Sep 17 00:00:00 2001 From: auxten Date: Tue, 28 May 2019 20:01:24 +0800 Subject: [PATCH 7/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c889caf1..4752d5ad1 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ [中文简介](https://github.com/CovenantSQL/CovenantSQL/blob/develop/README-zh.md) -CovenantSQL(CQL) is a Byzantine Fault Tolerance relational database built on SQLite: +CovenantSQL(CQL) is a **Byzantine Fault Tolerance** relational database built on SQLite: - **ServerLess**: Free, High Availabile, Auto Sync Database Service for Serverless App - **SQL**: Most SQL-92 support. From 4e6d2da2315740d9bdf365025364ad020026012d Mon Sep 17 00:00:00 2001 From: leventeliu Date: Thu, 30 May 2019 14:04:09 +0800 Subject: [PATCH 8/9] Fix bug: stopping worker before ack channel is exhausted --- client/conn.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/conn.go b/client/conn.go index 76be015ef..d0b2d3f47 100644 --- a/client/conn.go +++ b/client/conn.go @@ -159,11 +159,7 @@ func (c *pconn) startAckWorkers(workerCount int) (err error) { func (c *pconn) stopAckWorkers() { if c.ackCh != nil { - select { - case <-c.ackCh: - default: - close(c.ackCh) - } + close(c.ackCh) } } From 9ec2ee5fd981f2847fce779e2a85dd695b788bbd Mon Sep 17 00:00:00 2001 From: leventeliu Date: Thu, 30 May 2019 14:04:58 +0800 Subject: [PATCH 9/9] Check goroutine count after database connection is closed --- cmd/cql-minerd/integration_test.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/cmd/cql-minerd/integration_test.go b/cmd/cql-minerd/integration_test.go index 008ee9ab8..3dd048e24 100644 --- a/cmd/cql-minerd/integration_test.go +++ b/cmd/cql-minerd/integration_test.go @@ -746,13 +746,6 @@ func benchDB(b *testing.B, db *sql.DB, createDB bool) { }) }) - routineCount := runtime.NumGoroutine() - if routineCount > 500 { - b.Errorf("go routine count: %d", routineCount) - } else { - log.Infof("go routine count: %d", routineCount) - } - rowCount := db.QueryRow("SELECT COUNT(1) FROM " + TABLENAME) var count int64 err = rowCount.Scan(&count) @@ -788,13 +781,6 @@ func benchDB(b *testing.B, db *sql.DB, createDB bool) { }) }) - routineCount = runtime.NumGoroutine() - if routineCount > 500 { - b.Errorf("go routine count: %d", routineCount) - } else { - log.Infof("go routine count: %d", routineCount) - } - //row := db.QueryRow("SELECT nonIndexedColumn FROM test LIMIT 1") //var result int @@ -804,6 +790,13 @@ func benchDB(b *testing.B, db *sql.DB, createDB bool) { err = db.Close() So(err, ShouldBeNil) + + routineCount := runtime.NumGoroutine() + if routineCount > 500 { + b.Errorf("go routine count: %d", routineCount) + } else { + log.Infof("go routine count: %d", routineCount) + } } func benchMiner(b *testing.B, minerCount uint16) {