Skip to content
This repository was archived by the owner on Feb 21, 2024. It is now read-only.

Commit bb46213

Browse files
committed
Merge branch 'master' into release-1.0.1
All changes on master are bugfixes/doc changes.
2 parents 2d903e3 + f50685d commit bb46213

File tree

11 files changed

+133
-39
lines changed

11 files changed

+133
-39
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ clean:
2525
# Set up vendor directory using `dep`
2626
vendor: Gopkg.toml
2727
$(MAKE) require-dep
28-
dep ensure
28+
dep ensure -vendor-only
2929
touch vendor
3030

3131
# Run test suite

docs/webui.md docs/console.md

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
11
+++
2-
title = "WebUI"
2+
title = "Console"
33
weight = 9
44
nav = [
5-
"Console",
5+
"Installation",
6+
"Query",
67
"Cluster Admin",
78
]
89
+++
910

10-
## WebUI
11+
## Console
1112

12-
A web-based app called Pilosa WebUI is available in a separate package. This can be used for constructing queries and viewing the cluster status.
13+
A web-based app called Pilosa Console is available in a separate package. This can be used for constructing queries and viewing the cluster status.
1314

1415
### Installation
1516

16-
Releases are [available on Github](https://github.com/pilosa/webui/releases) as well as on [Homebrew](https://brew.sh/) for Mac.
17+
Releases are [available on Github](https://github.com/pilosa/console/releases) as well as on [Homebrew](https://brew.sh/) for Mac.
1718

1819
Installing on a Mac with Homebrew is simple; just run:
1920

2021
```
21-
brew install pilosa-webui
22+
brew tap pilosa/homebrew-pilosa
23+
brew install pilosa-console
2224
```
2325

24-
You may also build from source by checking out the [repo on Github](https://github.com/pilosa/webui) and running:
26+
You may also build from source by checking out the [repo on Github](https://github.com/pilosa/console) and running:
2527

2628
```
2729
make install
2830
```
2931

30-
### Console
32+
### Query
3133

32-
The Console view allows you to enter [PQL](../query-language/) queries and run them against your locally running server. First you must select an Index with the Select index dropdown.
34+
The Query tab allows you to enter [PQL](../query-language/) queries and run them against your locally running server. First you must select an Index with the Select index dropdown.
3335

3436
Each query's result will be displayed in the Output section along with the query time.
3537

3638
The Console will keep a record of each query and its result with the latest query on top.
3739

38-
![webUI console screenshot](/img/docs/webui-console.png)
39-
*WebUI console screenshot*
40+
![Console screenshot](/img/docs/webui-console.png)
41+
*Console query screenshot*
4042

4143
In addition to standard PQL, the console supports a few special commands, prefixed with `:`.
4244

encoding/proto/proto.go

+2
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ func encodeColumnAttrSets(a []*pilosa.ColumnAttrSet) []*internal.ColumnAttrSet {
961961
func encodeColumnAttrSet(set *pilosa.ColumnAttrSet) *internal.ColumnAttrSet {
962962
return &internal.ColumnAttrSet{
963963
ID: set.ID,
964+
Key: set.Key,
964965
Attrs: encodeAttrs(set.Attrs),
965966
}
966967
}
@@ -972,6 +973,7 @@ func encodeRow(r *pilosa.Row) *internal.Row {
972973

973974
return &internal.Row{
974975
Columns: r.Columns(),
976+
Keys: r.Keys,
975977
Attrs: encodeAttrs(r.Attrs),
976978
}
977979
}

executor_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,7 @@ func TestExecutor_Time_Clear_Quantums(t *testing.T) {
12791279
expected []uint64
12801280
}{
12811281
{quantum: "Y", expected: []uint64{3, 4, 5, 6}},
1282-
{quantum: "M", expected: []uint64{3, 4, 6}},
1282+
{quantum: "M", expected: []uint64{3, 4, 5, 6}},
12831283
{quantum: "D", expected: []uint64{3, 4, 5, 6}},
12841284
{quantum: "H", expected: []uint64{3, 4, 5, 6, 7}},
12851285
{quantum: "YM", expected: []uint64{3, 4, 5, 6}},

gossip/gossip.go

+11
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ func (g *memberSet) Open() (err error) {
9393
return nil
9494
}
9595

96+
// Close attempts to gracefully leave the cluster, and finally calls shutdown
97+
// after (at most) a timeout period.
98+
func (g *memberSet) Close() error {
99+
leaveErr := g.memberlist.Leave(5 * time.Second)
100+
shutdownErr := g.memberlist.Shutdown()
101+
if leaveErr != nil || shutdownErr != nil {
102+
return fmt.Errorf("leaving: '%v', shutting down: '%v'", leaveErr, shutdownErr)
103+
}
104+
return nil
105+
}
106+
96107
// joinWithRetry wraps the standard memberlist Join function in a retry.
97108
func (g *memberSet) joinWithRetry(hosts []string) error {
98109
err := retry(60, 2*time.Second, func() error {

http/handler.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type Handler struct {
5555

5656
ln net.Listener
5757

58+
closeTimeout time.Duration
59+
5860
server *http.Server
5961
}
6062

@@ -109,10 +111,20 @@ func OptHandlerListener(ln net.Listener) handlerOption {
109111
}
110112
}
111113

114+
// OptHandlerCloseTimeout controls how long to wait for the http Server to
115+
// shutdown cleanly before forcibly destroying it. Default is 30 seconds.
116+
func OptHandlerCloseTimeout(d time.Duration) handlerOption {
117+
return func(h *Handler) error {
118+
h.closeTimeout = d
119+
return nil
120+
}
121+
}
122+
112123
// NewHandler returns a new instance of Handler with a default logger.
113124
func NewHandler(opts ...handlerOption) (*Handler, error) {
114125
handler := &Handler{
115-
logger: pilosa.NopLogger,
126+
logger: pilosa.NopLogger,
127+
closeTimeout: time.Second * 30,
116128
}
117129
handler.Handler = newRouter(handler)
118130
handler.populateValidators()
@@ -146,10 +158,16 @@ func (h *Handler) Serve() error {
146158
return nil
147159
}
148160

161+
// Close tries to cleanly shutdown the HTTP server, and failing that, after a
162+
// timeout, calls Server.Close.
149163
func (h *Handler) Close() error {
150-
// TODO: timeout?
151-
err := h.server.Shutdown(context.Background())
152-
return errors.Wrap(err, "shutdown http server")
164+
deadlineCtx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(h.closeTimeout))
165+
defer cancelFunc()
166+
err := h.server.Shutdown(deadlineCtx)
167+
if err != nil {
168+
err = h.server.Close()
169+
}
170+
return errors.Wrap(err, "shutdown/close http server")
153171
}
154172

155173
func (h *Handler) populateValidators() {

server.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -369,17 +369,28 @@ func (s *Server) Close() error {
369369
close(s.closing)
370370
s.wg.Wait()
371371

372+
var errh error
373+
var errt error
374+
var errc error
372375
if s.cluster != nil {
373-
s.cluster.close()
376+
errc = s.cluster.close()
374377
}
375378
if s.holder != nil {
376-
s.holder.Close()
379+
errh = s.holder.Close()
377380
}
378381
if s.translateFile != nil {
379-
s.translateFile.Close()
380-
}
381-
382-
return nil
382+
errt = s.translateFile.Close()
383+
}
384+
// prefer to return holder error over translateFile error over cluster
385+
// error. This order is somewhat arbitrary. It would be better if we had
386+
// some way to combine all the errors, but probably not important enough to
387+
// warrant the extra complexity.
388+
if errh != nil {
389+
return errors.Wrap(errh, "closing holder")
390+
} else if errt != nil {
391+
return errors.Wrap(errt, "closing translateFile")
392+
}
393+
return errors.Wrap(errc, "closing cluster")
383394
}
384395

385396
// loadNodeID gets NodeID from disk, or creates a new value.

server/server.go

+27-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
package server
2121

2222
import (
23-
"fmt"
23+
"crypto/tls"
2424
"io"
2525
"log"
2626
"math/rand"
@@ -31,7 +31,7 @@ import (
3131
"syscall"
3232
"time"
3333

34-
"crypto/tls"
34+
"golang.org/x/sync/errgroup"
3535

3636
"github.com/pilosa/pilosa"
3737
"github.com/pilosa/pilosa/boltdb"
@@ -62,6 +62,7 @@ type Command struct {
6262

6363
// Gossip transport
6464
gossipTransport *gossip.Transport
65+
gossipMemberSet io.Closer
6566

6667
// Standard input/output
6768
*pilosa.CmdIO
@@ -75,9 +76,10 @@ type Command struct {
7576
logOutput io.Writer
7677
logger loggerLogger
7778

78-
Handler pilosa.Handler
79-
API *pilosa.API
80-
ln net.Listener
79+
Handler pilosa.Handler
80+
API *pilosa.API
81+
ln net.Listener
82+
closeTimeout time.Duration
8183

8284
serverOptions []pilosa.ServerOption
8385
}
@@ -91,6 +93,13 @@ func OptCommandServerOptions(opts ...pilosa.ServerOption) CommandOption {
9193
}
9294
}
9395

96+
func OptCommandCloseTimeout(d time.Duration) CommandOption {
97+
return func(c *Command) error {
98+
c.closeTimeout = d
99+
return nil
100+
}
101+
}
102+
94103
// NewCommand returns a new instance of Main.
95104
func NewCommand(stdin io.Reader, stdout, stderr io.Writer, opts ...CommandOption) *Command {
96105
c := &Command{
@@ -294,6 +303,7 @@ func (m *Command) SetupServer() error {
294303
http.OptHandlerAPI(m.API),
295304
http.OptHandlerLogger(m.logger),
296305
http.OptHandlerListener(m.ln),
306+
http.OptHandlerCloseTimeout(m.closeTimeout),
297307
)
298308
return errors.Wrap(err, "new handler")
299309

@@ -326,6 +336,8 @@ func (m *Command) setupNetworking() error {
326336
if err != nil {
327337
return errors.Wrap(err, "getting memberset")
328338
}
339+
m.gossipMemberSet = gossipMemberSet
340+
329341
return errors.Wrap(gossipMemberSet.Open(), "opening gossip memberset")
330342
}
331343

@@ -338,17 +350,18 @@ func (m *Command) GossipTransport() *gossip.Transport {
338350

339351
// Close shuts down the server.
340352
func (m *Command) Close() error {
341-
var logErr error
342-
handlerErr := m.Handler.Close()
343-
serveErr := m.Server.Close()
344-
if closer, ok := m.logOutput.(io.Closer); ok {
345-
logErr = closer.Close()
353+
defer close(m.done)
354+
eg := errgroup.Group{}
355+
eg.Go(m.Handler.Close)
356+
eg.Go(m.Server.Close)
357+
if m.gossipMemberSet != nil {
358+
eg.Go(m.gossipMemberSet.Close)
346359
}
347-
close(m.done)
348-
if serveErr != nil || logErr != nil || handlerErr != nil {
349-
return fmt.Errorf("closing server: '%v', closing logs: '%v', closing handler: '%v'", serveErr, logErr, handlerErr)
360+
if closer, ok := m.logOutput.(io.Closer); ok {
361+
eg.Go(closer.Close)
350362
}
351-
return nil
363+
err := eg.Wait()
364+
return errors.Wrap(err, "closing everything")
352365
}
353366

354367
// newStatsClient creates a stats client from the config

test/pilosa.go

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"os"
2424
"strings"
2525
"testing"
26+
"time"
2627

2728
"github.com/pilosa/pilosa/http"
2829
"github.com/pilosa/pilosa/server"
@@ -55,6 +56,11 @@ func newCommand(opts ...server.CommandOption) *Command {
5556
panic(err)
5657
}
5758

59+
// set aggressive close timeout by default to avoid hanging tests. This was
60+
// a problem with PDK tests which used go-pilosa as well. We put it at the
61+
// beginning of the option slice so that it can be overridden by user-passed
62+
// options.
63+
opts = append([]server.CommandOption{server.OptCommandCloseTimeout(time.Millisecond * 2)}, opts...)
5864
m := &Command{Command: server.NewCommand(os.Stdin, os.Stdout, os.Stderr, opts...), commandOptions: opts}
5965
m.Config.DataDir = path
6066
m.Config.Bind = "http://localhost:0"

time.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func viewsByTimeRange(name string, start, end time.Time, q TimeQuantum) []string
140140
break
141141
} else if t.Month() != 1 {
142142
results = append(results, viewByTimeUnit(name, t, 'M'))
143-
t = t.AddDate(0, 1, 0)
143+
t = addMonth(t)
144144
continue
145145
}
146146
}
@@ -159,7 +159,7 @@ func viewsByTimeRange(name string, start, end time.Time, q TimeQuantum) []string
159159
t = t.AddDate(1, 0, 0)
160160
} else if hasMonth && nextMonthGTE(t, end) {
161161
results = append(results, viewByTimeUnit(name, t, 'M'))
162-
t = t.AddDate(0, 1, 0)
162+
t = addMonth(t)
163163
} else if hasDay && nextDayGTE(t, end) {
164164
results = append(results, viewByTimeUnit(name, t, 'D'))
165165
t = t.AddDate(0, 0, 1)
@@ -174,6 +174,19 @@ func viewsByTimeRange(name string, start, end time.Time, q TimeQuantum) []string
174174
return results
175175
}
176176

177+
// addMonth adds a month similar to time.AddDate(0, 1, 0), but
178+
// in certain edge cases it doesn't normalize for days late in the month.
179+
// In the "YM" case where t.Day is greater than 28, there are
180+
// edge cases where using time.AddDate() to add a month will result
181+
// in two "months" being added (Jan 31 + 1mo = March 2).
182+
func addMonth(t time.Time) time.Time {
183+
if t.Day() > 28 {
184+
t = time.Date(t.Year(), t.Month(), 1, t.Hour(), 0, 0, 0, t.Location())
185+
}
186+
t = t.AddDate(0, 1, 0)
187+
return t
188+
}
189+
177190
func nextYearGTE(t time.Time, end time.Time) bool {
178191
next := t.AddDate(1, 0, 0)
179192
if next.Year() == end.Year() {

time_internal_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ func TestViewsByTimeRange(t *testing.T) {
9797
t.Fatalf("unexpected fields: %#v", a)
9898
}
9999
})
100+
t.Run("YM31up", func(t *testing.T) {
101+
a := viewsByTimeRange("F", mustParseTime("2001-10-31 00:00"), mustParseTime("2003-04-01 00:00"), mustParseTimeQuantum("YM"))
102+
if !reflect.DeepEqual(a, []string{"F_200110", "F_200111", "F_200112", "F_2002", "F_200301", "F_200302", "F_200303"}) {
103+
t.Fatalf("unexpected fields: %#v", a)
104+
}
105+
})
106+
t.Run("YM31mid", func(t *testing.T) {
107+
a := viewsByTimeRange("F", mustParseTime("1999-12-31 00:00"), mustParseTime("2000-04-01 00:00"), mustParseTimeQuantum("YM"))
108+
if !reflect.DeepEqual(a, []string{"F_199912", "F_200001", "F_200002", "F_200003"}) {
109+
t.Fatalf("unexpected fields: %#v", a)
110+
}
111+
})
112+
t.Run("YM31down", func(t *testing.T) {
113+
a := viewsByTimeRange("F", mustParseTime("2000-01-31 00:00"), mustParseTime("2001-04-01 00:00"), mustParseTimeQuantum("YM"))
114+
if !reflect.DeepEqual(a, []string{"F_2000", "F_200101", "F_200102", "F_200103"}) {
115+
t.Fatalf("unexpected fields: %#v", a)
116+
}
117+
})
100118
t.Run("YMD", func(t *testing.T) {
101119
a := viewsByTimeRange("F", mustParseTime("2000-11-28 00:00"), mustParseTime("2003-03-02 00:00"), mustParseTimeQuantum("YMD"))
102120
if !reflect.DeepEqual(a, []string{"F_20001128", "F_20001129", "F_20001130", "F_200012", "F_2001", "F_2002", "F_200301", "F_200302", "F_20030301"}) {

0 commit comments

Comments
 (0)