Proof-of-concept for using TiDB instead of MySQL #60
This commit is contained in:
parent
11ca54da3b
commit
43b860801c
|
@ -1,4 +1,4 @@
|
|||
FROM photoprism/development:20181112
|
||||
FROM photoprism/development:20181218
|
||||
|
||||
# Set up project directory
|
||||
WORKDIR "/go/src/github.com/photoprism/photoprism"
|
||||
|
|
8
Makefile
8
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
|
|
@ -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
|
||||
database-driver: tidb
|
||||
database-dsn: root:@tcp(localhost:4000)/photoprism?parseTime=true
|
|
@ -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
|
||||
MYSQL_DATABASE: photoprism
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
39
docker/tidb/Dockerfile
Normal file
39
docker/tidb/Dockerfile
Normal file
|
@ -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"]
|
217
docker/tidb/entrypoint.sh
Executable file
217
docker/tidb/entrypoint.sh
Executable file
|
@ -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 "$@"
|
77
go.mod
77
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
|
||||
)
|
||||
|
|
239
go.sum
239
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=
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ type Config interface {
|
|||
GetAppVersion() string
|
||||
GetAppCopyright() string
|
||||
IsDebug() bool
|
||||
DbServerIP() string
|
||||
DbServerPort() uint
|
||||
GetServerIP() string
|
||||
GetServerPort() int
|
||||
GetServerMode() string
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
24
internal/tidb/init.go
Normal file
24
internal/tidb/init.go
Normal file
|
@ -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
|
||||
}
|
368
internal/tidb/server.go
Normal file
368
internal/tidb/server.go
Normal file
|
@ -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()
|
||||
}
|
Loading…
Reference in a new issue