diff --git a/Dockerfile b/Dockerfile index c09a8039a..30ad46379 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM photoprism/development:20181112 +FROM photoprism/development:20181218 # Set up project directory WORKDIR "/go/src/github.com/photoprism/photoprism" diff --git a/Makefile b/Makefile index 5150f397f..f77c19f3c 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ export GO111MODULE=on GOIMPORTS=goimports BINARY_NAME=photoprism DOCKER_TAG=`date -u +%Y%m%d` +TIDB_VERSION=2.1.1 +DARKTABLE_VERSION="$(awk '$2 == "DARKTABLE_VERSION" { print $3; exit }' docker/darktable/Dockerfile)" all: download dep js build install: install-bin install-assets install-config @@ -56,14 +58,16 @@ deploy-tensorflow: scripts/docker-build.sh tensorflow $(DOCKER_TAG) scripts/docker-push.sh tensorflow $(DOCKER_TAG) deploy-darktable: - DARKTABLE_VERSION="$(awk '$2 == "DARKTABLE_VERSION" { print $3; exit }' docker/darktable/Dockerfile)" scripts/docker-build.sh darktable $(DARKTABLE_VERSION) scripts/docker-push.sh darktable $(DARKTABLE_VERSION) +deploy-tidb: + scripts/docker-build.sh tidb $(TIDB_VERSION) + scripts/docker-push.sh tidb $(TIDB_VERSION) fmt: goimports -w internal cmd go fmt ./internal/... ./cmd/... dep: go build -v ./... - go mod tidy upgrade: + go mod tidy go get -u \ No newline at end of file diff --git a/configs/photoprism.yml b/configs/photoprism.yml index 12ebcaa56..779ec880f 100644 --- a/configs/photoprism.yml +++ b/configs/photoprism.yml @@ -8,5 +8,5 @@ export-path: /srv/photoprism/photos/export server-host: server-mode: release server-port: 80 -database-driver: mysql -database-dsn: photoprism:photoprism@tcp(database:3306)/photoprism?parseTime=true \ No newline at end of file +database-driver: tidb +database-dsn: root:@tcp(localhost:4000)/photoprism?parseTime=true \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 48095f4f0..b71d82f40 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,10 +4,11 @@ services: photoprism: build: . image: photoprism/photoprism:develop - command: broadwayd -p 8080 -a 0.0.0.0 :5 + depends_on: + - database ports: - 2342:80 # Web Server (PhotoPrism) - - 2343:8080 # Broadwayd (HTML5 display server) + - 4000:4000 # Database (MySQL compatible) volumes: - .:/go/src/github.com/photoprism/photoprism environment: @@ -20,18 +21,10 @@ services: PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/assets/photos/originals" database: - image: mysql:latest + image: mysql:8.0.12 command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=1024 - ports: - - 13306:3306 - volumes: - - photoprism-database:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: photoprism MYSQL_USER: photoprism MYSQL_PASSWORD: photoprism - MYSQL_DATABASE: photoprism - -volumes: # keep this - photoprism-database: - driver: local \ No newline at end of file + MYSQL_DATABASE: photoprism \ No newline at end of file diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile index 8e0cb3a8e..8bde219f6 100644 --- a/docker/development/Dockerfile +++ b/docker/development/Dockerfile @@ -34,13 +34,15 @@ RUN apt-get update && apt-get upgrade && \ wget \ git \ mysql-client \ - libgtk-3-bin + libgtk-3-bin \ + tzdata # Install darktable (RAW to JPEG converter) RUN add-apt-repository ppa:pmjdebruijn/darktable-release && \ apt-get update && \ apt-get install darktable && \ - apt-get upgrade + apt-get upgrade && \ + apt-get dist-upgrade # Install TensorFlow C library RUN curl -L \ @@ -64,12 +66,12 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # Install Go -ENV GOLANG_VERSION 1.11.2 +ENV GOLANG_VERSION 1.11.4 RUN set -eux; \ \ url="https://golang.org/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz"; \ wget -O go.tgz "$url"; \ - echo "1dfe664fa3d8ad714bbd15a36627992effd150ddabd7523931f077b3926d736d *go.tgz" | sha256sum -c -; \ + echo "fb26c30e6a04ad937bbc657a1b5bba92f80096af1e8ee6da6430c045a8db3a5b *go.tgz" | sha256sum -c -; \ tar -C /usr/local -xzf go.tgz; \ rm go.tgz; \ export PATH="/usr/local/go/bin:$PATH"; \ @@ -102,8 +104,9 @@ ENV BROADWAY_DISPLAY :5 # Set up project directory WORKDIR "/go/src/github.com/photoprism/photoprism" -# Expose HTTP port plus 8080 for broadwayd (not running by default) +# Expose HTTP port plus 4000 for TiDB and 8080 for broadwayd (not running by default) EXPOSE 80 +EXPOSE 4000 EXPOSE 8080 # Keep container running (services can be started manually using a terminal) diff --git a/docker/photoprism/Dockerfile b/docker/photoprism/Dockerfile index f6b5cf0e3..611255bae 100644 --- a/docker/photoprism/Dockerfile +++ b/docker/photoprism/Dockerfile @@ -1,4 +1,4 @@ -FROM photoprism/development:20181112 as build +FROM photoprism/development:20181218 as build # Set up project directory WORKDIR "/go/src/github.com/photoprism/photoprism" @@ -18,6 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ unzip \ nano \ wget \ + tzdata \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* @@ -43,8 +44,9 @@ RUN apt-get update && \ # Show photoprism version RUN photoprism -v -# Expose HTTP port +# Expose HTTP & TiDB port EXPOSE 80 +EXPOSE 4000 # Start PhotoPrism server CMD photoprism start \ No newline at end of file diff --git a/docker/photoprism/docker-compose.yml b/docker/photoprism/docker-compose.yml index 6887fbf55..5e2d2d090 100644 --- a/docker/photoprism/docker-compose.yml +++ b/docker/photoprism/docker-compose.yml @@ -12,23 +12,12 @@ services: volumes: - ~/Photos:/srv/photoprism/photos # change ~/Photos to whatever directory you want to use on your local computer - photoprism-cache:/srv/photoprism/cache # keep this (thumbnail cache) + - photoprism-database:/srv/photoprism/database # keep this (database files) environment: PHOTOPRISM_IMPORT_PATH: /srv/photoprism/photos/Import # ~/Photos/Import (files to be imported to originals) PHOTOPRISM_EXPORT_PATH: /srv/photoprism/photos/Export # ~/Photos/Export (files exported from originals) PHOTOPRISM_ORIGINALS_PATH: /srv/photoprism/photos/Originals # ~/Photos/Originals (original jpeg, raw and meta files) - database: # keep this - image: mysql:latest - restart: always - command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=1024 - volumes: - - photoprism-database:/var/lib/mysql - environment: - MYSQL_ROOT_PASSWORD: photoprism - MYSQL_USER: photoprism - MYSQL_PASSWORD: photoprism - MYSQL_DATABASE: photoprism - volumes: # keep this photoprism-cache: driver: local diff --git a/docker/tidb/Dockerfile b/docker/tidb/Dockerfile new file mode 100644 index 000000000..733983144 --- /dev/null +++ b/docker/tidb/Dockerfile @@ -0,0 +1,39 @@ +# Builder image +FROM golang:1.11.4-alpine as builder + +ENV TIDB_VERSION 2.1.1 + +RUN apk add --no-cache \ + wget \ + make \ + git \ + unzip + +RUN git clone https://github.com/pingcap/tidb.git /go/src/github.com/pingcap/tidb + +WORKDIR /go/src/github.com/pingcap/tidb/ + +RUN git checkout tags/v$TIDB_VERSION && rm go.sum && GO111MODULE=on go mod tidy && make + +# Executable image +FROM alpine:3.8 + +COPY --from=builder /go/src/github.com/pingcap/tidb/bin/tidb-server /usr/local/bin/tidb-server + +RUN apk add --no-cache \ + mysql-client \ + gnupg \ + openssl \ + pwgen \ + bash \ + tzdata + +COPY /docker/tidb/entrypoint.sh /usr/local/bin/entrypoint.sh + +WORKDIR / + +EXPOSE 4000 + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] + +CMD ["/usr/local/bin/tidb-server"] \ No newline at end of file diff --git a/docker/tidb/entrypoint.sh b/docker/tidb/entrypoint.sh new file mode 100755 index 000000000..cabe14717 --- /dev/null +++ b/docker/tidb/entrypoint.sh @@ -0,0 +1,217 @@ +#!/bin/bash +set -eo pipefail +shopt -s nullglob + +# if command starts with an option, prepend tidb-server +if [ "${1:0:1}" = '-' ]; then + set -- tidb-server "$@" +fi + +# skip setup if they want an option that stops tidb-server +wantHelp= +for arg; do + case "$arg" in + -'?'|--help|--print-defaults|-V|--version) + wantHelp=1 + break + ;; + esac +done + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# usage: process_init_file FILENAME MYSQLCOMMAND... +# ie: process_init_file foo.sh mysql -uroot +# (process a single initializer file, based on its extension. we define this +# function here, so that initializer scripts (*.sh) can use the same logic, +# potentially recursively, or override the logic used in subsequent calls) +process_init_file() { + local f="$1"; shift + local mysql=( "$@" ) + + case "$f" in + *.sh) echo "$0: running $f"; . "$f" ;; + *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; + *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; + *) echo "$0: ignoring $f" ;; + esac + echo +} + +_check_config() { + toRun=( "$@" --verbose --help ) + if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then + cat >&2 <<-EOM + + ERROR: tidb-server failed while attempting to check config + command was: "${toRun[*]}" + + $errors + EOM + exit 1 + fi +} + +# Fetch value from server config +# We use tidb-server --verbose --help instead of my_print_defaults because the +# latter only show values present in config files, and not server defaults +_get_config() { + local conf="$1"; shift + "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null \ + | awk '$1 == "'"$conf"'" && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' + # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" +} + +# allow the container to be started with `--user` +if [ "$1" = 'tidb-server' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then + _check_config "$@" + DATADIR="$(_get_config 'datadir' "$@")" + mkdir -p "$DATADIR" + chown -R mysql:mysql "$DATADIR" + exec mysql "$BASH_SOURCE" "$@" +fi + +if [ "$1" = 'tidb-server' -a -z "$wantHelp" ]; then + # still need to check config, container may have started with --user + _check_config "$@" + # Get config + DATADIR="$(_get_config 'datadir' "$@")" + + if [ ! -d "$DATADIR/mysql" ]; then + file_env 'TIDB_ROOT_PASSWORD' + if [ -z "$TIDB_ROOT_PASSWORD" -a -z "$TIDB_ALLOW_EMPTY_PASSWORD" -a -z "$TIDB_RANDOM_ROOT_PASSWORD" ]; then + echo >&2 'error: database is uninitialized and password option is not specified ' + echo >&2 ' You need to specify one of TIDB_ROOT_PASSWORD, TIDB_ALLOW_EMPTY_PASSWORD and TIDB_RANDOM_ROOT_PASSWORD' + exit 1 + fi + + mkdir -p "$DATADIR" + + echo 'Initializing database' + "$@" --initialize-insecure + echo 'Database initialized' + + if command -v mysql_ssl_rsa_setup > /dev/null && [ ! -e "$DATADIR/server-key.pem" ]; then + # https://github.com/mysql/mysql-server/blob/23032807537d8dd8ee4ec1c4d40f0633cd4e12f9/packaging/deb-in/extra/mysql-systemd-start#L81-L84 + echo 'Initializing certificates' + mysql_ssl_rsa_setup --datadir="$DATADIR" + echo 'Certificates initialized' + fi + + SOCKET="$(_get_config 'socket' "$@")" + "$@" --socket="${SOCKET}" & + pid="$!" + + mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) + + for i in {30..0}; do + if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then + break + fi + echo 'MySQL init process in progress...' + sleep 1 + done + if [ "$i" = 0 ]; then + echo >&2 'MySQL init process failed.' + exit 1 + fi + + if [ -z "$TIDB_INITDB_SKIP_TZINFO" ]; then + # sed is for https://bugs.mysql.com/bug.php?id=20545 + mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql + fi + + if [ ! -z "$TIDB_RANDOM_ROOT_PASSWORD" ]; then + export TIDB_ROOT_PASSWORD="$(pwgen -1 32)" + echo "GENERATED ROOT PASSWORD: $TIDB_ROOT_PASSWORD" + fi + + rootCreate= + # default root to listen for connections from anywhere + file_env 'TIDB_ROOT_HOST' '%' + if [ ! -z "$TIDB_ROOT_HOST" -a "$TIDB_ROOT_HOST" != 'localhost' ]; then + # no, we don't care if read finds a terminating character in this heredoc + # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${TIDB_ROOT_HOST}' IDENTIFIED BY '${TIDB_ROOT_PASSWORD}' ; + GRANT ALL ON *.* TO 'root'@'${TIDB_ROOT_HOST}' WITH GRANT OPTION ; + EOSQL + fi + + "${mysql[@]}" <<-EOSQL + -- What's done in this file shouldn't be replicated + -- or products like mysql-fabric won't work + SET @@SESSION.SQL_LOG_BIN=0; + + ALTER USER 'root'@'localhost' IDENTIFIED BY '${TIDB_ROOT_PASSWORD}' ; + GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; + ${rootCreate} + DROP DATABASE IF EXISTS test ; + FLUSH PRIVILEGES ; + EOSQL + + if [ ! -z "$TIDB_ROOT_PASSWORD" ]; then + mysql+=( -p"${TIDB_ROOT_PASSWORD}" ) + fi + + file_env 'TIDB_DATABASE' + if [ "$TIDB_DATABASE" ]; then + echo "CREATE DATABASE IF NOT EXISTS \`$TIDB_DATABASE\` ;" | "${mysql[@]}" + mysql+=( "$TIDB_DATABASE" ) + fi + + file_env 'TIDB_USER' + file_env 'TIDB_PASSWORD' + if [ "$TIDB_USER" -a "$TIDB_PASSWORD" ]; then + echo "CREATE USER '$TIDB_USER'@'%' IDENTIFIED BY '$TIDB_PASSWORD' ;" | "${mysql[@]}" + + if [ "$TIDB_DATABASE" ]; then + echo "GRANT ALL ON \`$TIDB_DATABASE\`.* TO '$TIDB_USER'@'%' ;" | "${mysql[@]}" + fi + + echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}" + fi + + echo + ls /docker-entrypoint-initdb.d/ > /dev/null + for f in /docker-entrypoint-initdb.d/*; do + process_init_file "$f" "${mysql[@]}" + done + + if [ ! -z "$TIDB_ONETIME_PASSWORD" ]; then + "${mysql[@]}" <<-EOSQL + ALTER USER 'root'@'%' PASSWORD EXPIRE; + EOSQL + fi + if ! kill -s TERM "$pid" || ! wait "$pid"; then + echo >&2 'MySQL init process failed.' + exit 1 + fi + + echo + echo 'MySQL init process done. Ready for start up.' + echo + fi +fi + +exec "$@" \ No newline at end of file diff --git a/go.mod b/go.mod index fcd30ffc2..859188a9b 100644 --- a/go.mod +++ b/go.mod @@ -1,24 +1,40 @@ module github.com/photoprism/photoprism require ( - cloud.google.com/go v0.32.0 // indirect + cloud.google.com/go v0.34.0 // indirect github.com/RobCherry/vibrant v0.0.0-20160904011657-0680b8cf1c89 - github.com/araddon/dateparse v0.0.0-20181020190151-00e168d34895 + github.com/araddon/dateparse v0.0.0-20181123171228-21df004e09ca github.com/bamiaux/rez v0.0.0-20170731184118-29f4463c688b // indirect + github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d // indirect github.com/brett-lempereur/ish v0.0.0-20161214150457-bbdc45bcf55d - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect + github.com/coreos/etcd v3.3.10+incompatible // indirect + github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142 // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect + github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f // indirect github.com/disintegration/imaging v1.5.0 - github.com/djherbis/times v1.0.1 + github.com/djherbis/times v1.1.0 + github.com/dustin/go-humanize v1.0.0 // indirect github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect github.com/gin-gonic/gin v1.3.0 - github.com/go-sql-driver/mysql v1.4.0 // indirect + github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/gofrs/uuid v3.1.0+incompatible // indirect + github.com/gogo/protobuf v1.2.0 // indirect + github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect github.com/google/go-cmp v0.2.0 // indirect - github.com/gosimple/slug v1.3.0 - github.com/jinzhu/gorm v1.9.1 + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/mux v1.6.2 // indirect + github.com/gorilla/websocket v1.4.0 // indirect + github.com/gosimple/slug v1.4.2 + github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.6.2 // indirect + github.com/jinzhu/gorm v1.9.2 github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect - github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae // indirect + github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3 // indirect github.com/json-iterator/go v1.1.5 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28 @@ -28,26 +44,55 @@ require ( github.com/mattn/go-sqlite3 v1.10.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/montanaflynn/stats v0.0.0-20181214052348-945b007cb92f // indirect + github.com/myesui/uuid v1.0.0 // indirect + github.com/onsi/gomega v1.4.3 // indirect + github.com/opentracing/opentracing-go v1.0.2 + github.com/pingcap/check v0.0.0-20171206051426-1c287c953996 + github.com/pingcap/errors v0.11.0 + github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030 + github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929 + github.com/pingcap/parser v0.0.0-20181207085916-6c21d4344dfa + github.com/pingcap/pd v2.1.0-rc.4+incompatible + github.com/pingcap/tidb v0.0.0-20181212102244-990f859384b8 + github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03 + github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93 github.com/pkg/errors v0.8.0 - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v0.9.2 + github.com/prometheus/common v0.0.0-20181218105931-67670fe90761 // indirect github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect + github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446 // indirect github.com/rwcarlsen/goexif v0.0.0-20180518182100-8d986c03457a github.com/simplereach/timeutils v1.2.0 // indirect + github.com/sirupsen/logrus v1.2.0 + github.com/soheilhy/cmux v0.1.4 // indirect + github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 // indirect github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 github.com/stretchr/testify v1.2.2 github.com/tensorflow/tensorflow v1.12.0 - github.com/ugorji/go v1.1.1 // indirect + github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect + github.com/twinj/uuid v1.0.0 // indirect + github.com/uber-go/atomic v1.3.2 // indirect + github.com/uber/jaeger-client-go v2.8.0+incompatible + github.com/unrolled/render v0.0.0-20181210145518-4c664cb3ad2f // indirect github.com/urfave/cli v1.20.0 - golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd // indirect - golang.org/x/image v0.0.0-20181109232246-249dc8530c0e - golang.org/x/net v0.0.0-20181108082009-03003ca0c849 // indirect - golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect - golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 // indirect + go.uber.org/atomic v1.3.2 // indirect + go.uber.org/multierr v1.1.0 // indirect + go.uber.org/zap v1.9.1 // indirect + golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect + golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b + golang.org/x/net v0.0.0-20181217023233-e147a9138326 // indirect + golang.org/x/sys v0.0.0-20181217223516-dcdaa6325bcb // indirect + golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect google.golang.org/appengine v1.3.0 // indirect + google.golang.org/genproto v0.0.0-20181218023534-67d6565462c5 // indirect + google.golang.org/grpc v1.17.0 // indirect gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 // indirect gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect - gopkg.in/yaml.v2 v2.2.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/stretchr/testify.v1 v1.2.2 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/go.sum b/go.sum index 22429ef92..c6b19ff4b 100644 --- a/go.sum +++ b/go.sum @@ -1,51 +1,113 @@ -cloud.google.com/go v0.32.0 h1:DSt59WoyNcfAInilEpfvm2ugq8zvNyaHAm9MkzOwRQ4= -cloud.google.com/go v0.32.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/RobCherry/vibrant v0.0.0-20160904011657-0680b8cf1c89 h1:k8/G7/7+vhkmphbzRSHulomGLxKJnM6Dp5NJ2HePGwY= github.com/RobCherry/vibrant v0.0.0-20160904011657-0680b8cf1c89/go.mod h1:xu1tbmzBGes+jcIUU9yATLxmOoxdCZT0hUp5HY1c6/A= -github.com/araddon/dateparse v0.0.0-20181020190151-00e168d34895 h1:lwIUr70QH7g1mghNz/8e7WZ9uEzSCHrNzTdsaVtbWK0= -github.com/araddon/dateparse v0.0.0-20181020190151-00e168d34895/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7 h1:Fv9bK1Q+ly/ROk4aJsVMeuIwPel4bEnD8EPiI91nZMg= +github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/araddon/dateparse v0.0.0-20181123171228-21df004e09ca h1:7tLEgJZb8/+TI8fLso4lINkuSOI4DqQYwhFB+nRH7RQ= +github.com/araddon/dateparse v0.0.0-20181123171228-21df004e09ca/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/bamiaux/rez v0.0.0-20170731184118-29f4463c688b h1:5Ci5wpOL75rYF6RQGRoqhEAU6xLJ6n/D4SckXX1yB74= github.com/bamiaux/rez v0.0.0-20170731184118-29f4463c688b/go.mod h1:obBQGGIFbbv9KWg92Qu9UHeD94JXmHD1jovY/z6I3O8= +github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/blacktear23/go-proxyprotocol v0.0.0-20171102103907-62e368e1c470/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= +github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= +github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= github.com/brett-lempereur/ish v0.0.0-20161214150457-bbdc45bcf55d h1:oCP9o9IOvgi0A1biE1EkI/m+pViqJoCQjU/bAopLpBo= github.com/brett-lempereur/ish v0.0.0-20161214150457-bbdc45bcf55d/go.mod h1:sGi2C1jLbZM77czzwYX70vIkYV8Smll6xG93m96IZYw= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68mZX1lGBkTWyp3CLcenw9I94W2dLeRvMzcn9N4= +github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.2.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180202092358-40e2722dffea/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cznic/mathutil v0.0.0-20160613104831-78ad7f262603/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= +github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= +github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4= +github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f h1:WH0w/R4Yoey+04HhFxqZ6VX6I0d7RMyw5aXQ9UTvQPs= github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/disintegration/imaging v1.5.0 h1:uYqUhwNmLU4K1FN44vhqS4TZJRAA4RhBINgbQlKyGi0= github.com/disintegration/imaging v1.5.0/go.mod h1:9B/deIUIrliYkyMTuXJd6OUFLcrZ2tf+3Qlwnaf/CjU= -github.com/djherbis/times v1.0.1 h1:nVRrVOTFd2r0C7wCQdIDz/fqt8yO0EEzr5f6aXfXiS0= -github.com/djherbis/times v1.0.1/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/djherbis/times v1.1.0 h1:NFhBDODme0XNX+/5ETW9qL6v3Ty57psiXIQBrzzg44E= +github.com/djherbis/times v1.1.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8= +github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/etcd-io/gofail v0.0.0-20180808172546-51ce9a71510a/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= -github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v0.0.0-20170715192408-3955978caca4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20161217183710-316fb6d3f031/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/gosimple/slug v1.3.0 h1:NKQyQMjKkgCpD/Vd+wKtFc7N60bJNCLDubKU/UDKMFI= -github.com/gosimple/slug v1.3.0/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= -github.com/jinzhu/gorm v1.9.1 h1:lDSDtsCt5AGGSKTs8AHlSDbbgif4G4+CKJ8ETBDVHTA= -github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v0.0.0-20170228224354-599cba5e7b61/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ= +github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= +github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20171020063731-82921fcf811d/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20160910222444-6b7015e65d36/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= +github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae h1:8bBMcboXYVuo0WYH+rPe5mB8obO89a993hdTZ3phTjc= -github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= -github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= +github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28 h1:SzHLOWB819X9aUXh2ct6krDIoIujoTsj5J1rDMjkRyo= +github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28 h1:mkl3tvPHIuPaWsLtmHTybJeoVEW7cbePK73Ir8VtruA= github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08 h1:5MnxBC15uMxFv5FY/J/8vzyaBiArCOkMdFT9Jsw78iY= github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4= @@ -53,54 +115,151 @@ github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.0.0-20181214052348-945b007cb92f/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/myesui/uuid v1.0.0/go.mod h1:2CDfNgU0LR8mIdO8vdWd8i9gWWxLlcoIGGpSNgafq84= +github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7 h1:7KAv7KMGTTqSmYZtNdcNTgsos+vFzULLwyElndwn+5c= +github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7/go.mod h1:iWMfgwqYW+e8n5lC/jjNEhwcjbRDpl5NT7n2h+4UNcI= +github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef h1:K0Fn+DoFqNqktdZtdV3bPQ/0cuYh2H4rkg0tytX/07k= +github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef/go.mod h1:7WjlapSfwQyo6LNmIvEWzsW1hbBQfpUO4JWnuQRmva8= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pingcap/check v0.0.0-20171206051426-1c287c953996/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ= +github.com/pingcap/errors v0.11.0 h1:DCJQB8jrHbQ1VVlMFIrbj2ApScNNotVmkSNplu2yUt4= +github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030 h1:XJLuW0lsP7vAtQ2iPjZwvXZ14m5urp9No+Qr06ZZcTo= +github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= +github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929 h1:E24nIxjoFlFkwCMaC7+KtHdxBZ79p1h++xEjhBXJw0M= +github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929/go.mod h1:0gwbe1F2iBIjuQ9AH0DbQhL+Dpr5GofU8fgYyXk+ykk= +github.com/pingcap/parser v0.0.0-20181207085916-6c21d4344dfa h1:m6vqGJWtMKHr2RiyxdcHptRXAsYMAXcdbL6uGQkaMxg= +github.com/pingcap/parser v0.0.0-20181207085916-6c21d4344dfa/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE= +github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E= +github.com/pingcap/tidb v0.0.0-20181212102244-990f859384b8 h1:6+UOtK4N2KRXO2E0N0MpmfIpnevpqQ9/qy/S4cyXhY8= +github.com/pingcap/tidb v0.0.0-20181212102244-990f859384b8/go.mod h1:BV96JCQuOnXXYah19mM4k7BFPT8kC+NOKAnAsWGOD0U= +github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03 h1:xVuo5U+l6XAWHsb+xhkZ8zz3jerIwDfCHAO6kR2Kaog= +github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= +github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93 h1:gI5bOzLMxjUq6ui+md/JnT4pYpkzrABJ/PeYORWiYYs= +github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180426121432-d811d2e9bf89/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181218105931-67670fe90761 h1:z6tvbDJ5OLJ48FFmnksv04a78maSTRBUIhkdHYV5Y98= +github.com/prometheus/common v0.0.0-20181218105931-67670fe90761/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ= github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446 h1:/NRJ5vAYoqz+7sG51ubIDHXeWO8DlTSrToPu6q11ziA= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rwcarlsen/goexif v0.0.0-20180518182100-8d986c03457a h1:ZDZdsnbMuRSoVbq1gR47o005lfn2OwODNCr23zh9gSk= github.com/rwcarlsen/goexif v0.0.0-20180518182100-8d986c03457a/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= -github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA= github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8= +github.com/sirupsen/logrus v0.0.0-20170323161349-3bcb09397d6d/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20150829172844-0d12bf811670/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tensorflow/tensorflow v1.12.0 h1:fT4okrN4BkpgotWmDwS56wM6BdkRpTL0lLMzvkM+bLo= github.com/tensorflow/tensorflow v1.12.0/go.mod h1:itOSERT4trABok4UOoG+X4BoKds9F3rIsySdn+Lvu90= +github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twinj/uuid v0.0.0-20150629100731-70cac2bcd273/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= +github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk= +github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber/jaeger-client-go v2.8.0+incompatible h1:7DGH8Hqk6PirD+GE+bvCf0cLnspLuae7N1NcwMeQcyg= +github.com/uber/jaeger-client-go v2.8.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.1.0 h1:k1oxbz5ToLJtwCGmTlNSmfciXv/SPe1tnmNe+FqTl5w= +github.com/uber/jaeger-lib v1.1.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= +github.com/unrolled/render v0.0.0-20181210145518-4c664cb3ad2f/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd h1:VtIkGDhk0ph3t+THbvXHfMZ8QHgsBO39Nh52+74pq7w= -golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/image v0.0.0-20181109232246-249dc8530c0e h1:tKeLpam+QnQXh80ue3KM7AcmYlUyEn8j00wnh3XphNk= -golang.org/x/image v0.0.0-20181109232246-249dc8530c0e/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180503215945-1f94bef427e3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b h1:VHyIDlv3XkfCa5/a81uzaoDkHH4rr81Z62g+xlnO8uM= +golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181217023233-e147a9138326 h1:iCzOf0xz39Tstp+Tu/WwyGjUXCk34QhQORRxBeXXTA4= +golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181217223516-dcdaa6325bcb h1:zzdd4xkMwu/GRxhSUJaCPh4/jil9kAbsU7AUmXboO+A= +golang.org/x/sys v0.0.0-20181217223516-dcdaa6325bcb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= +google.golang.org/genproto v0.0.0-20180427144745-86e600f69ee4/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181218023534-67d6565462c5 h1:ZcmLUbATcwP+ZlsJ5pn5qeF9O3pC7U7mYpSnHH7RFFs= +google.golang.org/genproto v0.0.0-20181218023534-67d6565462c5/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/natefinch/lumberjack.v2 v2.0.0-20161104145732-dd45e6a67c53/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/commands/config_test.go b/internal/commands/config_test.go index 47a118ff3..f5c5d0607 100644 --- a/internal/commands/config_test.go +++ b/internal/commands/config_test.go @@ -25,8 +25,8 @@ import-path /srv/photoprism/photos/import export-path /srv/photoprism/photos/export cache-path /srv/photoprism/cache assets-path /go/src/github.com/photoprism/photoprism/assets -database-driver mysql -database-dsn photoprism:photoprism@tcp(database:3306)/photoprism?parseTime=true +database-driver tidb +database-dsn root:@tcp(localhost:4000)/photoprism?parseTime=true ` assert.Equal(t, expected, output) diff --git a/internal/commands/flags.go b/internal/commands/flags.go index af6b12e28..e557f559f 100644 --- a/internal/commands/flags.go +++ b/internal/commands/flags.go @@ -53,14 +53,14 @@ var GlobalFlags = []cli.Flag{ }, cli.StringFlag{ Name: "database-driver", - Usage: "database `DRIVER` (mysql, postgres or sqlite)", - Value: "mysql", + Usage: "database `DRIVER` (tidb or mysql)", + Value: "tidb", EnvVar: "PHOTOPRISM_DATABASE_DRIVER", }, cli.StringFlag{ Name: "database-dsn", Usage: "database data source name (`DSN`)", - Value: "photoprism:photoprism@tcp(database:3306)/photoprism?parseTime=true", + Value: "root:@tcp(localhost:4000)/photoprism?parseTime=true", EnvVar: "PHOTOPRISM_DATABASE_DSN", }, } diff --git a/internal/context/config.go b/internal/context/config.go index 8b96ef0f9..04fe27584 100644 --- a/internal/context/config.go +++ b/internal/context/config.go @@ -12,9 +12,15 @@ import ( "github.com/photoprism/photoprism/internal/frontend" "github.com/photoprism/photoprism/internal/fsutil" "github.com/photoprism/photoprism/internal/models" + "github.com/photoprism/photoprism/internal/tidb" "github.com/urfave/cli" ) +const ( + DbTiDB = "tidb" + DbMySQL = "mysql" +) + // Config provides a struct in which application configuration is stored. // Application code must use functions to get config values, for two reasons: // @@ -29,6 +35,9 @@ type Config struct { appCopyright string debug bool configFile string + dbServerIP string + dbServerPort uint + dbServerPath string serverIP string serverPort int serverMode string @@ -73,6 +82,18 @@ func (c *Config) SetValuesFromFile(fileName string) error { c.debug = debug } + if dbServerIP, err := yamlConfig.Get("db-host"); err == nil { + c.dbServerIP = dbServerIP + } + + if dbServerPort, err := yamlConfig.GetInt("db-port"); err == nil { + c.dbServerPort = uint(dbServerPort) + } + + if dbServerPath, err := yamlConfig.Get("db-path"); err == nil { + c.dbServerPath = dbServerPath + } + if serverIP, err := yamlConfig.Get("server-host"); err == nil { c.serverIP = serverIP } @@ -159,6 +180,18 @@ func (c *Config) SetValuesFromCliContext(ctx *cli.Context) error { c.databaseDsn = ctx.GlobalString("database-dsn") } + if ctx.IsSet("db-host") || c.dbServerIP == "" { + c.dbServerIP = ctx.String("db-host") + } + + if ctx.IsSet("db-port") || c.dbServerPort == 0 { + c.dbServerPort = ctx.Uint("db-port") + } + + if ctx.IsSet("db-path") || c.dbServerPath == "" { + c.dbServerPath = ctx.String("db-path") + } + if ctx.IsSet("server-host") || c.serverIP == "" { c.serverIP = ctx.String("server-host") } @@ -211,20 +244,46 @@ func (c *Config) CreateDirectories() error { return nil } -// connectToDatabase estabilishes a connection to a database given a driver. -// It tries to do this 12 times with a 5 second sleep intervall in between. +// connectToDatabase establishes a database connection. +// When used with the tidb driver, it may create a new database server instance. +// It tries to do this 12 times with a 5 second sleep interval in between. func (c *Config) connectToDatabase() error { - db, err := gorm.Open(c.databaseDriver, c.databaseDsn) + dbDriver := c.GetDatabaseDriver() + dbDsn := c.GetDatabaseDsn() + + isTiDB := false + initSuccess := false + + if dbDriver == DbTiDB { + isTiDB = true + dbDriver = DbMySQL + } + + db, err := gorm.Open(dbDriver, dbDsn) if err != nil || db == nil { + if isTiDB { + go tidb.Start(c.GetDatabasePath(), 4000, "", c.IsDebug()) + } + for i := 1; i <= 12; i++ { time.Sleep(5 * time.Second) - db, err = gorm.Open(c.databaseDriver, c.databaseDsn) + db, err = gorm.Open(dbDriver, dbDsn) if db != nil && err == nil { break } + + if isTiDB && !initSuccess { + err = tidb.InitDatabase(4000) + + if err != nil { + log.Println(err) + } else { + initSuccess = true + } + } } if err != nil || db == nil { @@ -262,6 +321,16 @@ func (c *Config) GetConfigFile() string { return c.configFile } +// DbServerIP returns the database server IP address (empty for all). +func (c *Config) DbServerIP() string { + return c.dbServerIP +} + +// DbServerPort returns the database server port. +func (c *Config) DbServerPort() uint { + return c.dbServerPort +} + // GetServerIP returns the server IP address (empty for all). func (c *Config) GetServerIP() string { return c.serverIP @@ -357,7 +426,7 @@ func (c *Config) GetPublicBuildPath() string { return c.GetPublicPath() + "/build" } -// GetDb gets a db connection. If it already is estabilished it will return that. +// GetDb returns the db connection. func (c *Config) GetDb() *gorm.DB { if c.db == nil { c.connectToDatabase() @@ -378,10 +447,6 @@ func (c *Config) MigrateDb() { &models.Camera{}, &models.Lens{}, &models.Country{}) - - if !db.Dialect().HasIndex("photos", "photos_fulltext") { - db.Exec("CREATE FULLTEXT INDEX photos_fulltext ON photos (photo_title, photo_description, photo_artist, photo_colors)") - } } // GetClientConfig returns a loaded and set configuration entity. diff --git a/internal/context/config_test.go b/internal/context/config_test.go index fcfabc0f0..092248357 100644 --- a/internal/context/config_test.go +++ b/internal/context/config_test.go @@ -34,6 +34,6 @@ func TestConfig_SetValuesFromFile(t *testing.T) { assert.Equal(t, "/srv/photoprism/photos/originals", c.GetOriginalsPath()) assert.Equal(t, "/srv/photoprism/photos/import", c.GetImportPath()) assert.Equal(t, "/srv/photoprism/photos/export", c.GetExportPath()) - assert.Equal(t, "mysql", c.GetDatabaseDriver()) - assert.Equal(t, "photoprism:photoprism@tcp(database:3306)/photoprism?parseTime=true", c.GetDatabaseDsn()) + assert.Equal(t, "tidb", c.GetDatabaseDriver()) + assert.Equal(t, "root:@tcp(localhost:4000)/photoprism?parseTime=true", c.GetDatabaseDsn()) } diff --git a/internal/photoprism/config.go b/internal/photoprism/config.go index 3483e064a..2fc220ccc 100644 --- a/internal/photoprism/config.go +++ b/internal/photoprism/config.go @@ -20,6 +20,8 @@ type Config interface { GetAppVersion() string GetAppCopyright() string IsDebug() bool + DbServerIP() string + DbServerPort() uint GetServerIP() string GetServerPort() int GetServerMode() string diff --git a/internal/photoprism/config_test.go b/internal/photoprism/config_test.go index 5ec9d1b99..9ad2509f9 100644 --- a/internal/photoprism/config_test.go +++ b/internal/photoprism/config_test.go @@ -58,8 +58,8 @@ func TestContextConfig_SetValuesFromFile(t *testing.T) { assert.Equal(t, "/srv/photoprism/photos/originals", c.GetOriginalsPath()) assert.Equal(t, "/srv/photoprism/photos/import", c.GetImportPath()) assert.Equal(t, "/srv/photoprism/photos/export", c.GetExportPath()) - assert.Equal(t, test.DatabaseDriver, c.GetDatabaseDriver()) - assert.Equal(t, test.DatabaseDsn, c.GetDatabaseDsn()) + assert.Equal(t, "tidb", c.GetDatabaseDriver()) + assert.Equal(t, "root:@tcp(localhost:4000)/photoprism?parseTime=true", c.GetDatabaseDsn()) } func TestTestConfig_ConnectToDatabase(t *testing.T) { diff --git a/internal/photoprism/search.go b/internal/photoprism/search.go index afab6194a..32b5b6cd0 100644 --- a/internal/photoprism/search.go +++ b/internal/photoprism/search.go @@ -117,7 +117,8 @@ func (s *Search) Photos(form forms.PhotoSearchForm) ([]PhotoSearchResult, error) Group("photos.id, files.id") if form.Query != "" { - q = q.Where("tags.tag_label LIKE ? OR MATCH (photo_title, photo_description, photo_artist, photo_colors) AGAINST (?)", "%"+strings.ToLower(form.Query)+"%", form.Query) + likeString := "%"+strings.ToLower(form.Query)+"%" + q = q.Where("tags.tag_label LIKE ? OR LOWER(photo_title) LIKE ?", likeString, likeString) } if form.CameraID > 0 { diff --git a/internal/test/config.go b/internal/test/config.go index 70ea5c984..b24d7757d 100644 --- a/internal/test/config.go +++ b/internal/test/config.go @@ -15,9 +15,11 @@ import ( "github.com/photoprism/photoprism/internal/models" ) -const DataURL = "https://dl.photoprism.org/fixtures/test.zip" -const DataHash = "1a59b358b80221ab3e76efb683ad72402f0b0844" -const ConfigFile = "../../configs/photoprism.yml" +const ( + DataURL = "https://dl.photoprism.org/fixtures/test.zip" + DataHash = "1a59b358b80221ab3e76efb683ad72402f0b0844" + ConfigFile = "../../configs/photoprism.yml" +) var DarktableCli = "/usr/bin/darktable-cli" var DataZip = "/tmp/photoprism/testdata.zip" @@ -125,13 +127,16 @@ func (c *Config) CreateDirectories() error { // connectToDatabase estabilishes a connection to a database given a driver. // It tries to do this 12 times with a 5 second sleep intervall in between. func (c *Config) connectToDatabase() error { - db, err := gorm.Open(c.GetDatabaseDriver(), c.GetDatabaseDsn()) + dbDriver := c.GetDatabaseDriver() + dbDsn := c.GetDatabaseDsn() + + db, err := gorm.Open(dbDriver, dbDsn) if err != nil || db == nil { for i := 1; i <= 12; i++ { time.Sleep(5 * time.Second) - db, err = gorm.Open(c.GetDatabaseDriver(), c.GetDatabaseDsn()) + db, err = gorm.Open(dbDriver, dbDsn) if db != nil && err == nil { break @@ -183,6 +188,16 @@ func (c *Config) GetServerPort() int { return 80 } +// DbServerIP returns the database server IP address (empty for all). +func (c *Config) DbServerIP() string { + return "127.0.0.1" +} + +// DbServerPort returns the database server port. +func (c *Config) DbServerPort() uint { + return 4001 +} + // GetServerMode returns the server mode. func (c *Config) GetServerMode() string { return "test" @@ -289,10 +304,6 @@ func (c *Config) MigrateDb() { &models.Camera{}, &models.Lens{}, &models.Country{}) - - if !db.Dialect().HasIndex("photos", "photos_fulltext") { - db.Exec("CREATE FULLTEXT INDEX photos_fulltext ON photos (photo_title, photo_description, photo_artist, photo_colors)") - } } // GetClientConfig returns a loaded and set configuration entity. diff --git a/internal/tidb/init.go b/internal/tidb/init.go new file mode 100644 index 000000000..12dcf61e6 --- /dev/null +++ b/internal/tidb/init.go @@ -0,0 +1,24 @@ +package tidb + +import ( + "database/sql" + "fmt" +) + +func InitDatabase(port uint) error { + db, err := sql.Open("mysql", fmt.Sprintf("root:@tcp(localhost:%d)/", port)) + + if err != nil { + return err + } + + defer db.Close() + + _, err = db.Exec("CREATE DATABASE photoprism") + + if err != nil { + return err + } + + return nil +} diff --git a/internal/tidb/server.go b/internal/tidb/server.go new file mode 100644 index 000000000..66511dbc5 --- /dev/null +++ b/internal/tidb/server.go @@ -0,0 +1,368 @@ +// Copyright 2015 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package tidb + +import ( + "flag" + "fmt" + "os" + "runtime" + "strconv" + "strings" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/pingcap/errors" + "github.com/pingcap/parser/mysql" + "github.com/pingcap/parser/terror" + "github.com/pingcap/pd/client" + pumpcli "github.com/pingcap/tidb-tools/tidb-binlog/pump_client" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/ddl" + "github.com/pingcap/tidb/domain" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/metrics" + plannercore "github.com/pingcap/tidb/planner/core" + "github.com/pingcap/tidb/privilege/privileges" + "github.com/pingcap/tidb/server" + "github.com/pingcap/tidb/session" + "github.com/pingcap/tidb/sessionctx/binloginfo" + "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/statistics" + "github.com/pingcap/tidb/store/mockstore" + "github.com/pingcap/tidb/store/tikv" + "github.com/pingcap/tidb/store/tikv/gcworker" + "github.com/pingcap/tidb/util/logutil" + "github.com/pingcap/tidb/util/printer" + "github.com/pingcap/tidb/util/signal" + "github.com/pingcap/tidb/util/systimemon" + "github.com/pingcap/tidb/x-server" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/push" + log "github.com/sirupsen/logrus" +) + +var ( + cfg *config.Config + storage kv.Storage + dom *domain.Domain + svr *server.Server + xsvr *xserver.Server + graceful bool +) + +// Start the TiDB server using the configuration provided +func Start(path string, port uint, host string, debug bool) { + registerStores() + registerMetrics() + loadConfig() + + cfg.Log.Level = "error" + cfg.Path = path + cfg.Store = "mocktikv" + if debug && host == "" { + cfg.Host = "0.0.0.0" + } else { + cfg.Host = "localhost" + } + cfg.Port = port + cfg.Status.ReportStatus = false + + validateConfig() + setGlobalVars() + setupLog() + setupTracing() // Should before createServer and after setup config. + printInfo() + setupBinlogClient() + setupMetrics() + createStoreAndDomain() + createServer() + signal.SetupSignalHandler(serverShutdown) + runServer() + cleanup() + os.Exit(0) +} + +func registerStores() { + err := session.RegisterStore("tikv", tikv.Driver{}) + terror.MustNil(err) + tikv.NewGCHandlerFunc = gcworker.NewGCWorker + err = session.RegisterStore("mocktikv", mockstore.MockDriver{}) + terror.MustNil(err) +} + +func registerMetrics() { + metrics.RegisterMetrics() +} + +func createStoreAndDomain() { + fullPath := fmt.Sprintf("%s://%s", cfg.Store, cfg.Path) + var err error + storage, err = session.NewStore(fullPath) + terror.MustNil(err) + // Bootstrap a session to load information schema. + dom, err = session.BootstrapSession(storage) + terror.MustNil(err) +} + +func setupBinlogClient() { + if !cfg.Binlog.Enable { + return + } + + if cfg.Binlog.IgnoreError { + binloginfo.SetIgnoreError(true) + } + + client, err := pumpcli.NewPumpsClient(cfg.Path, parseDuration(cfg.Binlog.WriteTimeout), pd.SecurityOption{ + CAPath: cfg.Security.ClusterSSLCA, + CertPath: cfg.Security.ClusterSSLCert, + KeyPath: cfg.Security.ClusterSSLKey, + }) + terror.MustNil(err) + + binloginfo.SetPumpsClient(client) + log.Infof("create pumps client success, ignore binlog error %v", cfg.Binlog.IgnoreError) +} + +// Prometheus push. +const zeroDuration = time.Duration(0) + +// pushMetric pushes metrics in background. +func pushMetric(addr string, interval time.Duration) { + if interval == zeroDuration || len(addr) == 0 { + log.Info("disable Prometheus push client") + return + } + log.Infof("start Prometheus push client with server addr %s and interval %s", addr, interval) + go prometheusPushClient(addr, interval) +} + +// prometheusPushClient pushes metrics to Prometheus Pushgateway. +func prometheusPushClient(addr string, interval time.Duration) { + // TODO: TiDB do not have uniq name, so we use host+port to compose a name. + job := "tidb" + for { + err := push.AddFromGatherer( + job, + map[string]string{"instance": instanceName()}, + addr, + prometheus.DefaultGatherer, + ) + if err != nil { + log.Errorf("could not push metrics to Prometheus Pushgateway: %v", err) + } + time.Sleep(interval) + } +} + +func instanceName() string { + hostname, err := os.Hostname() + if err != nil { + return "unknown" + } + return fmt.Sprintf("%s_%d", hostname, cfg.Port) +} + +// parseDuration parses lease argument string. +func parseDuration(lease string) time.Duration { + dur, err := time.ParseDuration(lease) + if err != nil { + dur, err = time.ParseDuration(lease + "s") + } + if err != nil || dur < 0 { + log.Fatalf("invalid lease duration %s", lease) + } + return dur +} + +func hasRootPrivilege() bool { + return os.Geteuid() == 0 +} + +func flagBoolean(name string, defaultVal bool, usage string) *bool { + if defaultVal == false { + // Fix #4125, golang do not print default false value in usage, so we append it. + usage = fmt.Sprintf("%s (default false)", usage) + return flag.Bool(name, defaultVal, usage) + } + return flag.Bool(name, defaultVal, usage) +} + +func loadConfig() { + cfg = config.GetGlobalConfig() +} + +func validateConfig() { + if cfg.Security.SkipGrantTable && !hasRootPrivilege() { + log.Error("TiDB run with skip-grant-table need root privilege.") + os.Exit(-1) + } + if _, ok := config.ValidStorage[cfg.Store]; !ok { + nameList := make([]string, 0, len(config.ValidStorage)) + for k, v := range config.ValidStorage { + if v { + nameList = append(nameList, k) + } + } + log.Errorf("\"store\" should be in [%s] only", strings.Join(nameList, ", ")) + os.Exit(-1) + } + if cfg.Store == "mocktikv" && cfg.RunDDL == false { + log.Errorf("can't disable DDL on mocktikv") + os.Exit(-1) + } + if cfg.Log.File.MaxSize > config.MaxLogFileSize { + log.Errorf("log max-size should not be larger than %d MB", config.MaxLogFileSize) + os.Exit(-1) + } + if cfg.XProtocol.XServer { + log.Error("X Server is not available") + os.Exit(-1) + } + cfg.OOMAction = strings.ToLower(cfg.OOMAction) + + // lower_case_table_names is allowed to be 0, 1, 2 + if cfg.LowerCaseTableNames < 0 || cfg.LowerCaseTableNames > 2 { + log.Errorf("lower-case-table-names should be 0 or 1 or 2.") + os.Exit(-1) + } +} + +func setGlobalVars() { + ddlLeaseDuration := parseDuration(cfg.Lease) + session.SetSchemaLease(ddlLeaseDuration) + runtime.GOMAXPROCS(int(cfg.Performance.MaxProcs)) + statsLeaseDuration := parseDuration(cfg.Performance.StatsLease) + session.SetStatsLease(statsLeaseDuration) + domain.RunAutoAnalyze = cfg.Performance.RunAutoAnalyze + statistics.FeedbackProbability = cfg.Performance.FeedbackProbability + statistics.MaxQueryFeedbackCount = int(cfg.Performance.QueryFeedbackLimit) + statistics.RatioOfPseudoEstimate = cfg.Performance.PseudoEstimateRatio + ddl.RunWorker = cfg.RunDDL + ddl.EnableSplitTableRegion = cfg.SplitTable + plannercore.AllowCartesianProduct = cfg.Performance.CrossJoin + privileges.SkipWithGrant = cfg.Security.SkipGrantTable + variable.ForcePriority = int32(mysql.Str2Priority(cfg.Performance.ForcePriority)) + + variable.SysVars[variable.TIDBMemQuotaQuery].Value = strconv.FormatInt(cfg.MemQuotaQuery, 10) + variable.SysVars["lower_case_table_names"].Value = strconv.Itoa(cfg.LowerCaseTableNames) + + plannercore.SetPreparedPlanCache(cfg.PreparedPlanCache.Enabled) + if plannercore.PreparedPlanCacheEnabled() { + plannercore.PreparedPlanCacheCapacity = cfg.PreparedPlanCache.Capacity + } + + if cfg.TiKVClient.GrpcConnectionCount > 0 { + tikv.MaxConnectionCount = cfg.TiKVClient.GrpcConnectionCount + } + tikv.GrpcKeepAliveTime = time.Duration(cfg.TiKVClient.GrpcKeepAliveTime) * time.Second + tikv.GrpcKeepAliveTimeout = time.Duration(cfg.TiKVClient.GrpcKeepAliveTimeout) * time.Second + + tikv.CommitMaxBackoff = int(parseDuration(cfg.TiKVClient.CommitTimeout).Seconds() * 1000) +} + +func setupLog() { + err := logutil.InitLogger(cfg.Log.ToLogConfig()) + terror.MustNil(err) +} + +func printInfo() { + // Make sure the TiDB info is always printed. + level := log.GetLevel() + log.SetLevel(log.InfoLevel) + printer.PrintTiDBInfo() + log.SetLevel(level) +} + +func createServer() { + var driver server.IDriver + driver = server.NewTiDBDriver(storage) + var err error + svr, err = server.NewServer(cfg, driver) + // Both domain and storage have started, so we have to clean them before exiting. + terror.MustNil(err, closeDomainAndStorage) + if cfg.XProtocol.XServer { + xcfg := &xserver.Config{ + Addr: fmt.Sprintf("%s:%d", cfg.XProtocol.XHost, cfg.XProtocol.XPort), + Socket: cfg.XProtocol.XSocket, + TokenLimit: cfg.TokenLimit, + } + xsvr, err = xserver.NewServer(xcfg) + terror.MustNil(err, closeDomainAndStorage) + } +} + +func serverShutdown(isgraceful bool) { + if isgraceful { + graceful = true + } + if xsvr != nil { + xsvr.Close() // Should close xserver before server. + } + svr.Close() +} + +func setupMetrics() { + // Enable the mutex profile, 1/10 of mutex blocking event sampling. + runtime.SetMutexProfileFraction(10) + systimeErrHandler := func() { + metrics.TimeJumpBackCounter.Inc() + } + callBackCount := 0 + sucessCallBack := func() { + callBackCount++ + // It is callback by monitor per second, we increase metrics.KeepAliveCounter per 5s. + if callBackCount >= 5 { + callBackCount = 0 + metrics.KeepAliveCounter.Inc() + } + } + go systimemon.StartMonitor(time.Now, systimeErrHandler, sucessCallBack) + + pushMetric(cfg.Status.MetricsAddr, time.Duration(cfg.Status.MetricsInterval)*time.Second) +} + +func setupTracing() { + tracingCfg := cfg.OpenTracing.ToTracingConfig() + tracer, _, err := tracingCfg.New("TiDB") + if err != nil { + log.Fatal("cannot initialize Jaeger Tracer", err) + } + opentracing.SetGlobalTracer(tracer) +} + +func runServer() { + err := svr.Run() + terror.MustNil(err) + if cfg.XProtocol.XServer { + err := xsvr.Run() + terror.MustNil(err) + } +} + +func closeDomainAndStorage() { + dom.Close() + err := storage.Close() + terror.Log(errors.Trace(err)) +} + +func cleanup() { + if graceful { + svr.GracefulDown() + } else { + svr.KillAllConnections() + } + closeDomainAndStorage() +}