Skip to content

Commit 0fcd578

Browse files
committed
Merge branch 'release/v0.7.1'
2 parents b1a2248 + 8a08998 commit 0fcd578

File tree

9 files changed

+67
-25
lines changed

9 files changed

+67
-25
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## v0.7.1 - 2015-04-19
6+
### Changed
7+
- Improved logging of connection errors.
8+
9+
### Fixed
10+
- Fixed bug causing empty times to be inserted into the DB even when the omitempty tag was set.
11+
- Fixed node status refresh loop leaking goroutines.
12+
513
## v0.7.0 - 2015-03-30
614

715
This release includes support for RethinkDB 2.0 and connecting to clusters. To connect to a cluster you should use the new `Addresses` field in `ConnectOpts`, for example:

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
[Go](http://golang.org/) driver for [RethinkDB](http://www.rethinkdb.com/)
88

99

10-
Current version: v0.7.0 (RethinkDB v2.0)
10+
Current version: v0.7.1 (RethinkDB v2.0)
11+
12+
Please note that this version of the driver only supports versions of RethinkDB using the v0.4 protocol (any versions of the driver older than RethinkDB 2.0 will not work).
1113

1214
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dancannon/gorethink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
1315

@@ -30,7 +32,9 @@ import (
3032

3133
var session *r.Session
3234

33-
session, err := Connect(address)
35+
session, err := r.Connect(r.ConnectOpts{
36+
Address: "localhost:28015",
37+
})
3438
if err != nil {
3539
log.Fatalln(err.Error())
3640
}
@@ -62,12 +66,12 @@ session.SetMaxOpenConns(5)
6266

6367
### Connect to a cluster
6468

65-
To connect to a RethinkDB cluster which has multiple nodes you can use the following syntax.
69+
To connect to a RethinkDB cluster which has multiple nodes you can use the following syntax. When connecting to a cluster with multiple nodes queries will be distributed between these nodes.
6670

6771
```go
6872
var session *r.Session
6973

70-
session, err := r.Conenct(r.ConnectOpts{
74+
session, err := r.Connect(r.ConnectOpts{
7175
Addresses: []string{"localhost:28015", "localhost:28016"},
7276
Database: "test",
7377
AuthKey: "14daak1cad13dj",
@@ -117,7 +121,6 @@ r.Db("database").Table("table").Between(1, 10, r.BetweenOpts{
117121
}).Run(session)
118122
```
119123

120-
121124
### Optional Arguments
122125

123126
As shown above in the Between example optional arguments are passed to the function as a struct. Each function that has optional arguments as a related struct. This structs are named in the format FunctionNameOpts, for example BetweenOpts is the related struct for Between.

cluster.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ func (c *Cluster) connectNodes(hosts []Host) {
191191
for _, host := range hosts {
192192
conn, err := NewConnection(host.String(), c.opts)
193193
if err != nil {
194+
log.Warnf("Error creating connection %s", err.Error())
194195
continue
195196
}
196197
defer conn.Close()
@@ -201,6 +202,7 @@ func (c *Cluster) connectNodes(hosts []Host) {
201202
c.opts,
202203
))
203204
if err != nil {
205+
log.Warnf("Error fetching cluster status %s", err)
204206
continue
205207
}
206208

connection.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ func (c *Connection) sendQuery(q Query) error {
143143

144144
// Set timeout
145145
if c.opts.Timeout == 0 {
146-
c.conn.SetDeadline(time.Time{})
146+
c.conn.SetWriteDeadline(time.Time{})
147147
} else {
148-
c.conn.SetDeadline(time.Now().Add(c.opts.Timeout))
148+
c.conn.SetWriteDeadline(time.Now().Add(c.opts.Timeout))
149149
}
150150

151151
// Send the JSON encoding of the query itself.
@@ -165,6 +165,13 @@ func (c *Connection) nextToken() int64 {
165165
}
166166

167167
func (c *Connection) readResponse() (*Response, error) {
168+
// Set timeout
169+
if c.opts.Timeout == 0 {
170+
c.conn.SetReadDeadline(time.Time{})
171+
} else {
172+
c.conn.SetReadDeadline(time.Now().Add(c.opts.Timeout))
173+
}
174+
168175
// Read response header (token+length)
169176
_, err := io.ReadFull(c.conn, c.headerBuf[:respHeaderLen])
170177
if err != nil {

connection_helper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/binary"
66
"fmt"
77
"io"
8+
"strings"
89

910
p "github.com/dancannon/gorethink/ql2"
1011
)
@@ -60,6 +61,7 @@ func (c *Connection) readHandshakeSuccess() error {
6061
// convert to string and remove trailing NUL byte
6162
response := string(line[:len(line)-1])
6263
if response != "SUCCESS" {
64+
response = strings.TrimSpace(response)
6365
// we failed authorization or something else terrible happened
6466
return RqlDriverError{fmt.Sprintf("Server dropped connection with message: \"%s\"", response)}
6567
}

doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package gorethink implements a Go driver for RethinkDB
22
//
3-
// Current version: v0.7.0 (RethinkDB v2.0)
3+
// Current version: v0.7.1 (RethinkDB v2.0)
44
// For more in depth information on how to use RethinkDB check out the API docs
55
// at http://rethinkdb.com/api
66
package gorethink

encoding/encoder_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"image"
55
"reflect"
66
"testing"
7+
"time"
78
)
89

910
var encodeExpected = map[string]interface{}{
@@ -74,6 +75,9 @@ type Optionals struct {
7475
Ir int `gorethink:"omitempty"` // actually named omitempty, not an option
7576
Io int `gorethink:"io,omitempty"`
7677

78+
Tr time.Time `gorethink:"tr"`
79+
To time.Time `gorethink:"to,omitempty"`
80+
7781
Slr []string `gorethink:"slr"`
7882
Slo []string `gorethink:"slo,omitempty"`
7983

@@ -84,22 +88,24 @@ type Optionals struct {
8488
var optionalsExpected = map[string]interface{}{
8589
"sr": "",
8690
"omitempty": int64(0),
91+
"tr": map[string]interface{}{"$reql_type$": "TIME", "epoch_time": 0, "timezone": "+00:00"},
8792
"slr": []interface{}{},
8893
"mr": map[string]interface{}{},
8994
}
9095

9196
func TestOmitEmpty(t *testing.T) {
9297
var o Optionals
9398
o.Sw = "something"
99+
o.Tr = time.Unix(0, 0)
94100
o.Mr = map[string]interface{}{}
95101
o.Mo = map[string]interface{}{}
96102

97103
got, err := Encode(&o)
98104
if err != nil {
99105
t.Fatal(err)
100106
}
101-
if !reflect.DeepEqual(got, optionalsExpected) {
102-
t.Errorf(" got: %v\nwant: %v\n", got, optionalsExpected)
107+
if !jsonEqual(got, optionalsExpected) {
108+
t.Errorf("\ngot: %#v\nwant: %#v\n", got, optionalsExpected)
103109
}
104110
}
105111

encoding/encoder_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (se *structEncoder) encode(v reflect.Value) interface{} {
133133

134134
for i, f := range se.fields {
135135
fv := fieldByIndex(v, f.index)
136-
if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
136+
if !fv.IsValid() || f.omitEmpty && se.isEmptyValue(fv) {
137137
continue
138138
}
139139

@@ -143,6 +143,14 @@ func (se *structEncoder) encode(v reflect.Value) interface{} {
143143
return m
144144
}
145145

146+
func (se *structEncoder) isEmptyValue(v reflect.Value) bool {
147+
if v.Type() == timeType {
148+
return v.Interface().(time.Time) == time.Time{}
149+
}
150+
151+
return isEmptyValue(v)
152+
}
153+
146154
func newStructEncoder(t reflect.Type) encoderFunc {
147155
fields := cachedTypeFields(t)
148156
se := &structEncoder{

node.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ type Node struct {
1414
Host Host
1515
aliases []Host
1616

17-
cluster *Cluster
18-
pool *Pool
19-
refreshTicker *time.Ticker
17+
cluster *Cluster
18+
pool *Pool
19+
refreshDoneChan chan struct{}
2020

2121
mu sync.RWMutex
2222
closed bool
@@ -25,14 +25,14 @@ type Node struct {
2525

2626
func newNode(id string, aliases []Host, cluster *Cluster, pool *Pool) *Node {
2727
node := &Node{
28-
ID: id,
29-
Host: aliases[0],
30-
aliases: aliases,
31-
cluster: cluster,
32-
pool: pool,
33-
health: 100,
28+
ID: id,
29+
Host: aliases[0],
30+
aliases: aliases,
31+
cluster: cluster,
32+
pool: pool,
33+
health: 100,
34+
refreshDoneChan: make(chan struct{}),
3435
}
35-
3636
// Start node refresh loop
3737
refreshInterval := cluster.opts.NodeRefreshInterval
3838
if refreshInterval <= 0 {
@@ -41,9 +41,15 @@ func newNode(id string, aliases []Host, cluster *Cluster, pool *Pool) *Node {
4141
}
4242

4343
go func() {
44-
node.refreshTicker = time.NewTicker(refreshInterval)
45-
for _ = range node.refreshTicker.C {
46-
node.Refresh()
44+
45+
refreshTicker := time.NewTicker(refreshInterval)
46+
for {
47+
select {
48+
case <-refreshTicker.C:
49+
node.Refresh()
50+
case <-node.refreshDoneChan:
51+
return
52+
}
4753
}
4854
}()
4955

@@ -73,7 +79,7 @@ func (n *Node) Close(optArgs ...CloseOpts) error {
7379
}
7480
}
7581

76-
n.refreshTicker.Stop()
82+
n.refreshDoneChan <- struct{}{}
7783
if n.pool != nil {
7884
n.pool.Close()
7985
}

0 commit comments

Comments
 (0)