Use time.Duration according to the time docs
Having a time.Duration measuring seconds is likely to cause problems at a later stage. This change retains configuration compatibility while adding idiomatic duration use.
This commit is contained in:
parent
2d884f92e9
commit
0fedecd392
4 changed files with 102 additions and 18 deletions
|
|
@ -17,6 +17,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/cayley/config"
|
"github.com/google/cayley/config"
|
||||||
"github.com/google/cayley/db"
|
"github.com/google/cayley/db"
|
||||||
|
|
@ -294,7 +295,7 @@ var (
|
||||||
cfg = &config.Config{
|
cfg = &config.Config{
|
||||||
DatabasePath: "30kmoviedata.nq.gz",
|
DatabasePath: "30kmoviedata.nq.gz",
|
||||||
DatabaseType: "memstore",
|
DatabaseType: "memstore",
|
||||||
GremlinTimeout: 300,
|
GremlinTimeout: 300 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
ts graph.TripleStore
|
ts graph.TripleStore
|
||||||
|
|
|
||||||
|
|
@ -17,29 +17,112 @@ package config
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/barakmich/glog"
|
"github.com/barakmich/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
DatabaseType string
|
||||||
|
DatabasePath string
|
||||||
|
DatabaseOptions map[string]interface{}
|
||||||
|
ListenHost string
|
||||||
|
ListenPort string
|
||||||
|
ReadOnly bool
|
||||||
|
GremlinTimeout time.Duration
|
||||||
|
LoadSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {
|
||||||
DatabaseType string `json:"database"`
|
DatabaseType string `json:"database"`
|
||||||
DatabasePath string `json:"db_path"`
|
DatabasePath string `json:"db_path"`
|
||||||
DatabaseOptions map[string]interface{} `json:"db_options"`
|
DatabaseOptions map[string]interface{} `json:"db_options"`
|
||||||
ListenHost string `json:"listen_host"`
|
ListenHost string `json:"listen_host"`
|
||||||
ListenPort string `json:"listen_port"`
|
ListenPort string `json:"listen_port"`
|
||||||
ReadOnly bool `json:"read_only"`
|
ReadOnly bool `json:"read_only"`
|
||||||
GremlinTimeout int `json:"gremlin_timeout"`
|
GremlinTimeout duration `json:"gremlin_timeout"`
|
||||||
LoadSize int `json:"load_size"`
|
LoadSize int `json:"load_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var databasePath = flag.String("dbpath", "/tmp/testdb", "Path to the database.")
|
func (c *Config) UnmarshalJSON(data []byte) error {
|
||||||
var databaseBackend = flag.String("db", "memstore", "Database Backend.")
|
var t config
|
||||||
var host = flag.String("host", "0.0.0.0", "Host to listen on (defaults to all).")
|
err := json.Unmarshal(data, &t)
|
||||||
var loadSize = flag.Int("load_size", 10000, "Size of triplesets to load")
|
if err != nil {
|
||||||
var port = flag.String("port", "64210", "Port to listen on.")
|
return err
|
||||||
var readOnly = flag.Bool("read_only", false, "Disable writing via HTTP.")
|
}
|
||||||
var gremlinTimeout = flag.Int("gremlin_timeout", 30, "Number of seconds until an individual query times out.")
|
*c = Config{
|
||||||
|
DatabaseType: t.DatabaseType,
|
||||||
|
DatabasePath: t.DatabasePath,
|
||||||
|
DatabaseOptions: t.DatabaseOptions,
|
||||||
|
ListenHost: t.ListenHost,
|
||||||
|
ListenPort: t.ListenPort,
|
||||||
|
ReadOnly: t.ReadOnly,
|
||||||
|
GremlinTimeout: time.Duration(t.GremlinTimeout),
|
||||||
|
LoadSize: t.LoadSize,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(config{
|
||||||
|
DatabaseType: c.DatabaseType,
|
||||||
|
DatabasePath: c.DatabasePath,
|
||||||
|
DatabaseOptions: c.DatabaseOptions,
|
||||||
|
ListenHost: c.ListenHost,
|
||||||
|
ListenPort: c.ListenPort,
|
||||||
|
ReadOnly: c.ReadOnly,
|
||||||
|
GremlinTimeout: duration(c.GremlinTimeout),
|
||||||
|
LoadSize: c.LoadSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// duration is a time.Duration that satisfies the
|
||||||
|
// json.UnMarshaler and json.Marshaler interfaces.
|
||||||
|
type duration time.Duration
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals a duration according to the following scheme:
|
||||||
|
// * If the element is absent the duration is zero.
|
||||||
|
// * If the element is parsable as a time.Duration, the parsed value is kept.
|
||||||
|
// * If the element is parsable as a number, that number of seconds is kept.
|
||||||
|
func (d *duration) UnmarshalJSON(data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
*d = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
text := string(data)
|
||||||
|
t, err := time.ParseDuration(text)
|
||||||
|
if err == nil {
|
||||||
|
*d = duration(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(text, 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
*d = duration(time.Duration(i) * time.Second)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// This hack is to get around strconv.ParseFloat
|
||||||
|
// not handling e-notation for integers.
|
||||||
|
f, err := strconv.ParseFloat(text, 64)
|
||||||
|
*d = duration(time.Duration(f) * time.Second)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *duration) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf("%q", *d)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
databasePath = flag.String("dbpath", "/tmp/testdb", "Path to the database.")
|
||||||
|
databaseBackend = flag.String("db", "memstore", "Database Backend.")
|
||||||
|
host = flag.String("host", "0.0.0.0", "Host to listen on (defaults to all).")
|
||||||
|
loadSize = flag.Int("load_size", 10000, "Size of triplesets to load")
|
||||||
|
port = flag.String("port", "64210", "Port to listen on.")
|
||||||
|
readOnly = flag.Bool("read_only", false, "Disable writing via HTTP.")
|
||||||
|
gremlinTimeout = flag.Duration("gremlin_timeout", 30*time.Second, "Elapsed time until an individual query times out.")
|
||||||
|
)
|
||||||
|
|
||||||
func ParseConfigFromFile(filename string) *Config {
|
func ParseConfigFromFile(filename string) *Config {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@ All command line flags take precedence over the configuration file.
|
||||||
|
|
||||||
#### **`gremlin_timeout`**
|
#### **`gremlin_timeout`**
|
||||||
|
|
||||||
* Type: Integer
|
* Type: Integer or String
|
||||||
* Default: 30
|
* Default: 30
|
||||||
|
|
||||||
The value in seconds of the maximum length of time the Javascript runtime should run until cancelling the query and returning a 408 Timeout. A negative value means no limit.
|
The maximum length of time the Javascript runtime should run until cancelling the query and returning a 408 Timeout. When gremlin_timeout is an integer is is interpretted as seconds, when it is a string it is [parsed](http://golang.org/pkg/time/#ParseDuration) as a Go time.Duration. A negative duration means no limit.
|
||||||
|
|
||||||
## Per-Database Options
|
## Per-Database Options
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,15 @@ type Session struct {
|
||||||
err error
|
err error
|
||||||
script *otto.Script
|
script *otto.Script
|
||||||
kill chan struct{}
|
kill chan struct{}
|
||||||
timeoutSec time.Duration
|
timeout time.Duration
|
||||||
emptyEnv *otto.Otto
|
emptyEnv *otto.Otto
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSession(ts graph.TripleStore, timeoutSec int, persist bool) *Session {
|
func NewSession(ts graph.TripleStore, timeout time.Duration, persist bool) *Session {
|
||||||
g := Session{
|
g := Session{
|
||||||
ts: ts,
|
ts: ts,
|
||||||
limit: -1,
|
limit: -1,
|
||||||
timeoutSec: time.Duration(timeoutSec),
|
timeout: timeout,
|
||||||
}
|
}
|
||||||
g.env = BuildEnviron(&g)
|
g.env = BuildEnviron(&g)
|
||||||
if persist {
|
if persist {
|
||||||
|
|
@ -125,9 +125,9 @@ func (s *Session) runUnsafe(input interface{}) (otto.Value, error) {
|
||||||
// Use buffered chan to prevent blocking.
|
// Use buffered chan to prevent blocking.
|
||||||
s.env.Interrupt = make(chan func(), 1)
|
s.env.Interrupt = make(chan func(), 1)
|
||||||
|
|
||||||
if s.timeoutSec >= 0 {
|
if s.timeout >= 0 {
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(s.timeoutSec * time.Second)
|
time.Sleep(s.timeout)
|
||||||
close(s.kill)
|
close(s.kill)
|
||||||
s.envLock.Lock()
|
s.envLock.Lock()
|
||||||
defer s.envLock.Unlock()
|
defer s.envLock.Unlock()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue