Merge branch 'github:master' into master
This commit is contained in:
commit
ac23094497
12
build.sh
12
build.sh
@ -18,7 +18,7 @@ function build {
|
|||||||
GOOS=$3
|
GOOS=$3
|
||||||
GOARCH=$4
|
GOARCH=$4
|
||||||
|
|
||||||
if ! go version | egrep -q 'go(1\.1[56])' ; then
|
if ! go version | egrep -q 'go1\.(1[5-9]|[2-9][0-9]{1})' ; then
|
||||||
echo "go version must be 1.15 or above"
|
echo "go version must be 1.15 or above"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -40,8 +40,9 @@ function build {
|
|||||||
builddir=$(setuptree)
|
builddir=$(setuptree)
|
||||||
cp $buildpath/$target $builddir/gh-ost/usr/bin
|
cp $buildpath/$target $builddir/gh-ost/usr/bin
|
||||||
cd $buildpath
|
cd $buildpath
|
||||||
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'shlomi-noach <shlomi-noach+gh-ost-deb@github.com>' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t rpm --rpm-rpmbuild-define "_build_id_links none" .
|
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'GitHub' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t rpm --rpm-rpmbuild-define "_build_id_links none" .
|
||||||
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'shlomi-noach <shlomi-noach+gh-ost-deb@github.com>' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t deb --deb-no-default-config-files .
|
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'GitHub' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t deb --deb-no-default-config-files .
|
||||||
|
cd -
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,10 +63,13 @@ main() {
|
|||||||
mkdir -p ${buildpath}
|
mkdir -p ${buildpath}
|
||||||
rm -rf ${buildpath:?}/*
|
rm -rf ${buildpath:?}/*
|
||||||
build GNU/Linux linux linux amd64
|
build GNU/Linux linux linux amd64
|
||||||
# build macOS osx darwin amd64
|
build macOS osx darwin amd64
|
||||||
|
|
||||||
echo "Binaries found in:"
|
echo "Binaries found in:"
|
||||||
find $buildpath/gh-ost* -type f -maxdepth 1
|
find $buildpath/gh-ost* -type f -maxdepth 1
|
||||||
|
|
||||||
|
echo "Checksums:"
|
||||||
|
(cd $buildpath && shasum -a256 gh-ost* 2>/dev/null)
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
@ -22,7 +22,7 @@ If, for some reason, you do not wish `gh-ost` to connect to a replica, you may c
|
|||||||
|
|
||||||
### approve-renamed-columns
|
### approve-renamed-columns
|
||||||
|
|
||||||
When your migration issues a column rename (`change column old_name new_name ...`) `gh-ost` analyzes the statement to try and associate the old column name with new column name. Otherwise the new structure may also look like some column was dropped and another was added.
|
When your migration issues a column rename (`change column old_name new_name ...`) `gh-ost` analyzes the statement to try and associate the old column name with new column name. Otherwise, the new structure may also look like some column was dropped and another was added.
|
||||||
|
|
||||||
`gh-ost` will print out what it thinks the _rename_ implied, but will not issue the migration unless you provide with `--approve-renamed-columns`.
|
`gh-ost` will print out what it thinks the _rename_ implied, but will not issue the migration unless you provide with `--approve-renamed-columns`.
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ If you think `gh-ost` is mistaken and that there's actually no _rename_ involved
|
|||||||
|
|
||||||
`gh-ost` infers the identity of the master server by crawling up the replication topology. You may explicitly tell `gh-ost` the identity of the master host via `--assume-master-host=the.master.com`. This is useful in:
|
`gh-ost` infers the identity of the master server by crawling up the replication topology. You may explicitly tell `gh-ost` the identity of the master host via `--assume-master-host=the.master.com`. This is useful in:
|
||||||
|
|
||||||
- _master-master_ topologies (together with [`--allow-master-master`](#allow-master-master)), where `gh-ost` can arbitrarily pick one of the co-masters and you prefer that it picks a specific one
|
- _master-master_ topologies (together with [`--allow-master-master`](#allow-master-master)), where `gh-ost` can arbitrarily pick one of the co-masters, and you prefer that it picks a specific one
|
||||||
- _tungsten replicator_ topologies (together with [`--tungsten`](#tungsten)), where `gh-ost` is unable to crawl and detect the master
|
- _tungsten replicator_ topologies (together with [`--tungsten`](#tungsten)), where `gh-ost` is unable to crawl and detect the master
|
||||||
|
|
||||||
### assume-rbr
|
### assume-rbr
|
||||||
@ -61,7 +61,13 @@ Comma delimited status-name=threshold, same format as [`--max-load`](#max-load).
|
|||||||
|
|
||||||
`--critical-load` defines a threshold that, when met, `gh-ost` panics and bails out. The default behavior is to bail out immediately when meeting this threshold.
|
`--critical-load` defines a threshold that, when met, `gh-ost` panics and bails out. The default behavior is to bail out immediately when meeting this threshold.
|
||||||
|
|
||||||
This may sometimes lead to migrations bailing out on a very short spike, that, while in itself is impacting production and is worth investigating, isn't reason enough to kill a 10 hour migration.
|
This may sometimes lead to migrations bailing out on a very short spike, that, while in itself is impacting production and is worth investigating, isn't reason enough to kill a 10-hour migration.
|
||||||
|
|
||||||
|
### critical-load-hibernate-seconds
|
||||||
|
|
||||||
|
When `--critical-load-hibernate-seconds` is non-zero (e.g. `--critical-load-hibernate-seconds=300`), `critical-load` does not panic and bail out; instead, `gh-ost` goes into hibernation for the specified duration. It will not read/write anything from/to any server during this time. Execution then continues upon waking from hibernation.
|
||||||
|
|
||||||
|
If `critical-load` is met again, `gh-ost` will repeat this cycle, and never panic and bail out.
|
||||||
|
|
||||||
### critical-load-interval-millis
|
### critical-load-interval-millis
|
||||||
|
|
||||||
@ -98,7 +104,7 @@ Noteworthy is that setting `--dml-batch-size` to higher value _does not_ mean `g
|
|||||||
|
|
||||||
### exact-rowcount
|
### exact-rowcount
|
||||||
|
|
||||||
A `gh-ost` execution need to copy whatever rows you have in your existing table onto the ghost table. This can, and often be, a large number. Exactly what that number is?
|
A `gh-ost` execution need to copy whatever rows you have in your existing table onto the ghost table. This can and often will be, a large number. Exactly what that number is?
|
||||||
`gh-ost` initially estimates the number of rows in your table by issuing an `explain select * from your_table`. This will use statistics on your table and return with a rough estimate. How rough? It might go as low as half or as high as double the actual number of rows in your table. This is the same method as used in [`pt-online-schema-change`](https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html).
|
`gh-ost` initially estimates the number of rows in your table by issuing an `explain select * from your_table`. This will use statistics on your table and return with a rough estimate. How rough? It might go as low as half or as high as double the actual number of rows in your table. This is the same method as used in [`pt-online-schema-change`](https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html).
|
||||||
|
|
||||||
`gh-ost` also supports the `--exact-rowcount` flag. When this flag is given, two things happen:
|
`gh-ost` also supports the `--exact-rowcount` flag. When this flag is given, two things happen:
|
||||||
@ -135,6 +141,10 @@ Add this flag when executing on a 1st generation Google Cloud Platform (GCP).
|
|||||||
|
|
||||||
Default 100. See [`subsecond-lag`](subsecond-lag.md) for details.
|
Default 100. See [`subsecond-lag`](subsecond-lag.md) for details.
|
||||||
|
|
||||||
|
### hooks-status-interval
|
||||||
|
|
||||||
|
Defaults to 60 seconds. Configures how often the `gh-ost-on-status` hook is called, see [`hooks`](hooks.md) for full details on how to use hooks.
|
||||||
|
|
||||||
### initially-drop-ghost-table
|
### initially-drop-ghost-table
|
||||||
|
|
||||||
`gh-ost` maintains two tables while migrating: the _ghost_ table (which is synced from your original table and finally replaces it) and a changelog table, which is used internally for bookkeeping. By default, it panics and aborts if it sees those tables upon startup. Provide `--initially-drop-ghost-table` and `--initially-drop-old-table` to let `gh-ost` know it's OK to drop them beforehand.
|
`gh-ost` maintains two tables while migrating: the _ghost_ table (which is synced from your original table and finally replaces it) and a changelog table, which is used internally for bookkeeping. By default, it panics and aborts if it sees those tables upon startup. Provide `--initially-drop-ghost-table` and `--initially-drop-old-table` to let `gh-ost` know it's OK to drop them beforehand.
|
||||||
@ -230,7 +240,7 @@ Provide a command delimited list of replicas; `gh-ost` will throttle when any of
|
|||||||
|
|
||||||
### throttle-http
|
### throttle-http
|
||||||
|
|
||||||
Provide a HTTP endpoint; `gh-ost` will issue `HEAD` requests on given URL and throttle whenever response status code is not `200`. The URL can be queried and updated dynamically via [interactive commands](interactive-commands.md). Empty URL disables the HTTP check.
|
Provide an HTTP endpoint; `gh-ost` will issue `HEAD` requests on given URL and throttle whenever response status code is not `200`. The URL can be queried and updated dynamically via [interactive commands](interactive-commands.md). Empty URL disables the HTTP check.
|
||||||
|
|
||||||
### timestamp-old-table
|
### timestamp-old-table
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ The following variables are available on all hooks:
|
|||||||
- `GH_OST_INSPECTED_LAG` - lag in seconds (floating point) of inspected server
|
- `GH_OST_INSPECTED_LAG` - lag in seconds (floating point) of inspected server
|
||||||
- `GH_OST_HEARTBEAT_LAG` - lag in seconds (floating point) of heartbeat
|
- `GH_OST_HEARTBEAT_LAG` - lag in seconds (floating point) of heartbeat
|
||||||
- `GH_OST_PROGRESS` - progress pct ([0..100], floating point) of migration
|
- `GH_OST_PROGRESS` - progress pct ([0..100], floating point) of migration
|
||||||
|
- `GH_OST_ETA_SECONDS` - estimated duration until migration finishes in seconds
|
||||||
- `GH_OST_MIGRATED_HOST`
|
- `GH_OST_MIGRATED_HOST`
|
||||||
- `GH_OST_INSPECTED_HOST`
|
- `GH_OST_INSPECTED_HOST`
|
||||||
- `GH_OST_EXECUTING_HOST`
|
- `GH_OST_EXECUTING_HOST`
|
||||||
|
@ -112,7 +112,7 @@ It is also interesting to observe that `gh-ost` is the only application writing
|
|||||||
|
|
||||||
When `gh-ost` pauses (throttles), it issues no writes on the ghost table. Because there are no triggers, write workload is decoupled from the `gh-ost` write workload. And because we're using an asynchronous approach, the algorithm already handles a time difference between a master write time and the ghost apply time. A difference of a few microseconds is no different from a difference of minutes or hours.
|
When `gh-ost` pauses (throttles), it issues no writes on the ghost table. Because there are no triggers, write workload is decoupled from the `gh-ost` write workload. And because we're using an asynchronous approach, the algorithm already handles a time difference between a master write time and the ghost apply time. A difference of a few microseconds is no different from a difference of minutes or hours.
|
||||||
|
|
||||||
When `gh-ost` [throttles](throttle.md), either by replication lag, `max-load` setting or and explicit [interactive user command](interactive-commands.md), the master is back to normal. It sees no more writes on the ghost table.
|
When `gh-ost` [throttles](throttle.md), either by replication lag, `max-load` setting or an explicit [interactive user command](interactive-commands.md), the master is back to normal. It sees no more writes on the ghost table.
|
||||||
An exception is the ongoing heartbeat writes onto the changelog table, which we consider to be negligible.
|
An exception is the ongoing heartbeat writes onto the changelog table, which we consider to be negligible.
|
||||||
|
|
||||||
#### Testability
|
#### Testability
|
||||||
|
7
go.mod
7
go.mod
@ -4,15 +4,14 @@ go 1.16
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-ini/ini v1.62.0
|
github.com/go-ini/ini v1.62.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-mysql-org/go-mysql v1.3.0
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/openark/golib v0.0.0-20210531070646-355f37940af8
|
github.com/openark/golib v0.0.0-20210531070646-355f37940af8
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/siddontang/go-mysql v1.1.0
|
|
||||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7
|
||||||
golang.org/x/text v0.3.5
|
golang.org/x/text v0.3.6
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
)
|
)
|
||||||
|
92
go.sum
92
go.sum
@ -1,32 +1,54 @@
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/cznic/golex v0.0.0-20181122101858-9c343928389c/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
|
||||||
|
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||||
|
github.com/cznic/parser v0.0.0-20160622100904-31edd927e5b1/go.mod h1:2B43mz36vGZNZEwkWi8ayRSSUXLfjL8OkbzwW4NcPMM=
|
||||||
|
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
|
||||||
|
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||||
|
github.com/cznic/y v0.0.0-20170802143616-045f81c6662a/go.mod h1:1rk5VM7oSnA4vjp+hrLQ3HWHa+Y4yPCa3/CsJrcNnvs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
|
github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
|
||||||
github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-mysql-org/go-mysql v1.3.0 h1:lpNqkwdPzIrYSZGdqt8HIgAXZaK6VxBNfr8f7Z4FgGg=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-mysql-org/go-mysql v1.3.0/go.mod h1:3lFZKf7l95Qo70+3XB2WpiSf9wu2s3na3geLMaIIrqQ=
|
||||||
|
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/openark/golib v0.0.0-20210531070646-355f37940af8 h1:9ciIHNuyFqRWi9NpMNw9sVLB6z1ItpP5ZhTY9Q1xVu4=
|
github.com/openark/golib v0.0.0-20210531070646-355f37940af8 h1:9ciIHNuyFqRWi9NpMNw9sVLB6z1ItpP5ZhTY9Q1xVu4=
|
||||||
github.com/openark/golib v0.0.0-20210531070646-355f37940af8/go.mod h1:1jj8x1eDVZxgc/Z4VyamX4qTbAdHPUQA6NeVtCd8Sl8=
|
github.com/openark/golib v0.0.0-20210531070646-355f37940af8/go.mod h1:1jj8x1eDVZxgc/Z4VyamX4qTbAdHPUQA6NeVtCd8Sl8=
|
||||||
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
|
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
|
||||||
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
|
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/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/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
github.com/pingcap/parser v0.0.0-20190506092653-e336082eb825/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
|
github.com/pingcap/errors v0.11.5-0.20201029093017-5a7df2af2ac7/go.mod h1:G7x87le1poQzLB/TqvTJI2ILrSgobnq4Ut7luOwvfvI=
|
||||||
github.com/pingcap/tipb v0.0.0-20190428032612-535e1abaa330/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI=
|
github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3 h1:LllgC9eGfqzkfubMgjKIDyZYaa609nNWAyNZtpy2B3M=
|
||||||
|
github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3/go.mod h1:G7x87le1poQzLB/TqvTJI2ILrSgobnq4Ut7luOwvfvI=
|
||||||
|
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
|
||||||
|
github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
|
||||||
|
github.com/pingcap/parser v0.0.0-20210415081931-48e7f467fd74/go.mod h1:xZC8I7bug4GJ5KtHhgAikjTfU4kBv1Sbo3Pf1MZ6lVw=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||||
@ -35,38 +57,76 @@ github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8
|
|||||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||||
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 h1:oI+RNwuC9jF2g2lP0u0cVEEZrc/AYBCuFdvwrLWM/6Q=
|
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 h1:oI+RNwuC9jF2g2lP0u0cVEEZrc/AYBCuFdvwrLWM/6Q=
|
||||||
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
|
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
|
||||||
github.com/siddontang/go-mysql v1.1.0 h1:NfkS1skrPwUd3hsUqhc6jrv24dKTNMANxKRmDsf1fMc=
|
|
||||||
github.com/siddontang/go-mysql v1.1.0/go.mod h1:+W4RCzesQDI11HvIkaDjS8yM36SpAnGNQ7jmTLn5BnU=
|
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
|
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.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
@ -140,6 +140,7 @@ type MigrationContext struct {
|
|||||||
HooksHintMessage string
|
HooksHintMessage string
|
||||||
HooksHintOwner string
|
HooksHintOwner string
|
||||||
HooksHintToken string
|
HooksHintToken string
|
||||||
|
HooksStatusIntervalSec int64
|
||||||
|
|
||||||
DropServeSocket bool
|
DropServeSocket bool
|
||||||
ServeSocketFile string
|
ServeSocketFile string
|
||||||
@ -551,8 +552,8 @@ func (this *MigrationContext) SetMaxLagMillisecondsThrottleThreshold(maxLagMilli
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *MigrationContext) SetChunkSize(chunkSize int64) {
|
func (this *MigrationContext) SetChunkSize(chunkSize int64) {
|
||||||
if chunkSize < 100 {
|
if chunkSize < 10 {
|
||||||
chunkSize = 100
|
chunkSize = 10
|
||||||
}
|
}
|
||||||
if chunkSize > 100000 {
|
if chunkSize > 100000 {
|
||||||
chunkSize = 100000
|
chunkSize = 100000
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2016 GitHub Inc.
|
Copyright 2021 GitHub Inc.
|
||||||
See https://github.com/github/gh-ost/blob/master/LICENSE
|
See https://github.com/github/gh-ost/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/github/gh-ost/go/mysql"
|
"github.com/github/gh-ost/go/mysql"
|
||||||
"github.com/github/gh-ost/go/sql"
|
"github.com/github/gh-ost/go/sql"
|
||||||
|
|
||||||
gomysql "github.com/siddontang/go-mysql/mysql"
|
gomysql "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
"github.com/siddontang/go-mysql/replication"
|
"github.com/go-mysql-org/go-mysql/replication"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -98,7 +99,7 @@ func main() {
|
|||||||
flag.BoolVar(&migrationContext.AssumeRBR, "assume-rbr", false, "set to 'true' when you know for certain your server uses 'ROW' binlog_format. gh-ost is unable to tell, event after reading binlog_format, whether the replication process does indeed use 'ROW', and restarts replication to be certain RBR setting is applied. Such operation requires SUPER privileges which you might not have. Setting this flag avoids restarting replication and you can proceed to use gh-ost without SUPER privileges")
|
flag.BoolVar(&migrationContext.AssumeRBR, "assume-rbr", false, "set to 'true' when you know for certain your server uses 'ROW' binlog_format. gh-ost is unable to tell, event after reading binlog_format, whether the replication process does indeed use 'ROW', and restarts replication to be certain RBR setting is applied. Such operation requires SUPER privileges which you might not have. Setting this flag avoids restarting replication and you can proceed to use gh-ost without SUPER privileges")
|
||||||
flag.BoolVar(&migrationContext.CutOverExponentialBackoff, "cut-over-exponential-backoff", false, "Wait exponentially longer intervals between failed cut-over attempts. Wait intervals obey a maximum configurable with 'exponential-backoff-max-interval').")
|
flag.BoolVar(&migrationContext.CutOverExponentialBackoff, "cut-over-exponential-backoff", false, "Wait exponentially longer intervals between failed cut-over attempts. Wait intervals obey a maximum configurable with 'exponential-backoff-max-interval').")
|
||||||
exponentialBackoffMaxInterval := flag.Int64("exponential-backoff-max-interval", 64, "Maximum number of seconds to wait between attempts when performing various operations with exponential backoff.")
|
exponentialBackoffMaxInterval := flag.Int64("exponential-backoff-max-interval", 64, "Maximum number of seconds to wait between attempts when performing various operations with exponential backoff.")
|
||||||
chunkSize := flag.Int64("chunk-size", 1000, "amount of rows to handle in each iteration (allowed range: 100-100,000)")
|
chunkSize := flag.Int64("chunk-size", 1000, "amount of rows to handle in each iteration (allowed range: 10-100,000)")
|
||||||
dmlBatchSize := flag.Int64("dml-batch-size", 10, "batch size for DML events to apply in a single transaction (range 1-100)")
|
dmlBatchSize := flag.Int64("dml-batch-size", 10, "batch size for DML events to apply in a single transaction (range 1-100)")
|
||||||
defaultRetries := flag.Int64("default-retries", 60, "Default number of retries for various operations before panicking")
|
defaultRetries := flag.Int64("default-retries", 60, "Default number of retries for various operations before panicking")
|
||||||
cutOverLockTimeoutSeconds := flag.Int64("cut-over-lock-timeout-seconds", 3, "Max number of seconds to hold locks on tables while attempting to cut-over (retry attempted when lock exceeds timeout)")
|
cutOverLockTimeoutSeconds := flag.Int64("cut-over-lock-timeout-seconds", 3, "Max number of seconds to hold locks on tables while attempting to cut-over (retry attempted when lock exceeds timeout)")
|
||||||
@ -124,13 +125,14 @@ func main() {
|
|||||||
flag.StringVar(&migrationContext.HooksHintMessage, "hooks-hint", "", "arbitrary message to be injected to hooks via GH_OST_HOOKS_HINT, for your convenience")
|
flag.StringVar(&migrationContext.HooksHintMessage, "hooks-hint", "", "arbitrary message to be injected to hooks via GH_OST_HOOKS_HINT, for your convenience")
|
||||||
flag.StringVar(&migrationContext.HooksHintOwner, "hooks-hint-owner", "", "arbitrary name of owner to be injected to hooks via GH_OST_HOOKS_HINT_OWNER, for your convenience")
|
flag.StringVar(&migrationContext.HooksHintOwner, "hooks-hint-owner", "", "arbitrary name of owner to be injected to hooks via GH_OST_HOOKS_HINT_OWNER, for your convenience")
|
||||||
flag.StringVar(&migrationContext.HooksHintToken, "hooks-hint-token", "", "arbitrary token to be injected to hooks via GH_OST_HOOKS_HINT_TOKEN, for your convenience")
|
flag.StringVar(&migrationContext.HooksHintToken, "hooks-hint-token", "", "arbitrary token to be injected to hooks via GH_OST_HOOKS_HINT_TOKEN, for your convenience")
|
||||||
|
flag.Int64Var(&migrationContext.HooksStatusIntervalSec, "hooks-status-interval", 60, "how many seconds to wait between calling onStatus hook")
|
||||||
|
|
||||||
flag.UintVar(&migrationContext.ReplicaServerId, "replica-server-id", 99999, "server id used by gh-ost process. Default: 99999")
|
flag.UintVar(&migrationContext.ReplicaServerId, "replica-server-id", 99999, "server id used by gh-ost process. Default: 99999")
|
||||||
|
|
||||||
maxLoad := flag.String("max-load", "", "Comma delimited status-name=threshold. e.g: 'Threads_running=100,Threads_connected=500'. When status exceeds threshold, app throttles writes")
|
maxLoad := flag.String("max-load", "", "Comma delimited status-name=threshold. e.g: 'Threads_running=100,Threads_connected=500'. When status exceeds threshold, app throttles writes")
|
||||||
criticalLoad := flag.String("critical-load", "", "Comma delimited status-name=threshold, same format as --max-load. When status exceeds threshold, app panics and quits")
|
criticalLoad := flag.String("critical-load", "", "Comma delimited status-name=threshold, same format as --max-load. When status exceeds threshold, app panics and quits")
|
||||||
flag.Int64Var(&migrationContext.CriticalLoadIntervalMilliseconds, "critical-load-interval-millis", 0, "When 0, migration immediately bails out upon meeting critical-load. When non-zero, a second check is done after given interval, and migration only bails out if 2nd check still meets critical load")
|
flag.Int64Var(&migrationContext.CriticalLoadIntervalMilliseconds, "critical-load-interval-millis", 0, "When 0, migration immediately bails out upon meeting critical-load. When non-zero, a second check is done after given interval, and migration only bails out if 2nd check still meets critical load")
|
||||||
flag.Int64Var(&migrationContext.CriticalLoadHibernateSeconds, "critical-load-hibernate-seconds", 0, "When nonzero, critical-load does not panic and bail out; instead, gh-ost goes into hibernate for the specified duration. It will not read/write anything to from/to any server")
|
flag.Int64Var(&migrationContext.CriticalLoadHibernateSeconds, "critical-load-hibernate-seconds", 0, "When non-zero, critical-load does not panic and bail out; instead, gh-ost goes into hibernation for the specified duration. It will not read/write anything from/to any server")
|
||||||
quiet := flag.Bool("quiet", false, "quiet")
|
quiet := flag.Bool("quiet", false, "quiet")
|
||||||
verbose := flag.Bool("verbose", false, "verbose")
|
verbose := flag.Bool("verbose", false, "verbose")
|
||||||
debug := flag.Bool("debug", false, "debug mode (very verbose)")
|
debug := flag.Bool("debug", false, "debug mode (very verbose)")
|
||||||
@ -188,6 +190,11 @@ func main() {
|
|||||||
log.Fatalf("--database must be provided and database name must not be empty, or --alter must specify database name")
|
log.Fatalf("--database must be provided and database name must not be empty, or --alter must specify database name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := flag.Set("database", url.QueryEscape(migrationContext.DatabaseName)); err != nil {
|
||||||
|
migrationContext.Log.Fatale(err)
|
||||||
|
}
|
||||||
|
|
||||||
if migrationContext.OriginalTableName == "" {
|
if migrationContext.OriginalTableName == "" {
|
||||||
if parser.HasExplicitTable() {
|
if parser.HasExplicitTable() {
|
||||||
migrationContext.OriginalTableName = parser.GetExplicitTable()
|
migrationContext.OriginalTableName = parser.GetExplicitTable()
|
||||||
|
@ -1016,7 +1016,7 @@ func (this *Migrator) printStatus(rule PrintStatusRule, writers ...io.Writer) {
|
|||||||
w := io.MultiWriter(writers...)
|
w := io.MultiWriter(writers...)
|
||||||
fmt.Fprintln(w, status)
|
fmt.Fprintln(w, status)
|
||||||
|
|
||||||
if elapsedSeconds%60 == 0 {
|
if elapsedSeconds%this.migrationContext.HooksStatusIntervalSec == 0 {
|
||||||
this.hooksExecutor.onStatus(status)
|
this.hooksExecutor.onStatus(status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
|
"github.com/go-mysql-org/go-mysql/packet"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go-mysql/packet"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultAuthPluginName = AUTH_NATIVE_PASSWORD
|
const defaultAuthPluginName = AUTH_NATIVE_PASSWORD
|
||||||
@ -46,7 +46,7 @@ func (c *Conn) readInitialHandshake() error {
|
|||||||
pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1
|
pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1
|
||||||
|
|
||||||
// connection id length is 4
|
// connection id length is 4
|
||||||
c.connectionID = uint32(binary.LittleEndian.Uint32(data[pos : pos+4]))
|
c.connectionID = binary.LittleEndian.Uint32(data[pos : pos+4])
|
||||||
pos += 4
|
pos += 4
|
||||||
|
|
||||||
c.salt = []byte{}
|
c.salt = []byte{}
|
||||||
@ -106,7 +106,7 @@ func (c *Conn) readInitialHandshake() error {
|
|||||||
// generate auth response data according to auth plugin
|
// generate auth response data according to auth plugin
|
||||||
//
|
//
|
||||||
// NOTE: the returned boolean value indicates whether to add a \NUL to the end of data.
|
// NOTE: the returned boolean value indicates whether to add a \NUL to the end of data.
|
||||||
// it is quite tricky because MySQl server expects different formats of responses in different auth situations.
|
// it is quite tricky because MySQL server expects different formats of responses in different auth situations.
|
||||||
// here the \NUL needs to be added when sending back the empty password or cleartext password in 'sha256_password'
|
// here the \NUL needs to be added when sending back the empty password or cleartext password in 'sha256_password'
|
||||||
// authentication.
|
// authentication.
|
||||||
func (c *Conn) genAuthResponse(authData []byte) ([]byte, bool, error) {
|
func (c *Conn) genAuthResponse(authData []byte) ([]byte, bool, error) {
|
||||||
@ -199,7 +199,7 @@ func (c *Conn) writeAuthHandshake() error {
|
|||||||
|
|
||||||
// Charset [1 byte]
|
// Charset [1 byte]
|
||||||
// use default collation id 33 here, is utf-8
|
// use default collation id 33 here, is utf-8
|
||||||
data[12] = byte(DEFAULT_COLLATION_ID)
|
data[12] = DEFAULT_COLLATION_ID
|
||||||
|
|
||||||
// SSL Connection Request Packet
|
// SSL Connection Request Packet
|
||||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
|
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
|
@ -7,9 +7,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
|
"github.com/go-mysql-org/go-mysql/packet"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go-mysql/packet"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
@ -33,6 +33,9 @@ type Conn struct {
|
|||||||
connectionID uint32
|
connectionID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function will be called for every row in resultset from ExecuteSelectStreaming.
|
||||||
|
type SelectPerRowCallback func(row []FieldValue) error
|
||||||
|
|
||||||
func getNetProto(addr string) string {
|
func getNetProto(addr string) string {
|
||||||
proto := "tcp"
|
proto := "tcp"
|
||||||
if strings.Contains(addr, "/") {
|
if strings.Contains(addr, "/") {
|
||||||
@ -165,6 +168,28 @@ func (c *Conn) Execute(command string, args ...interface{}) (*Result, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecuteSelectStreaming will call perRowCallback for every row in resultset
|
||||||
|
// WITHOUT saving any row data to Result.{Values/RawPkg/RowDatas} fields.
|
||||||
|
//
|
||||||
|
// ExecuteSelectStreaming should be used only for SELECT queries with a large response resultset for memory preserving.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// var result mysql.Result
|
||||||
|
// conn.ExecuteSelectStreaming(`SELECT ... LIMIT 100500`, &result, func(row []mysql.FieldValue) error {
|
||||||
|
// // Use the row as you want.
|
||||||
|
// // You must not save FieldValue.AsString() value after this callback is done. Copy it if you need.
|
||||||
|
// return nil
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
func (c *Conn) ExecuteSelectStreaming(command string, result *Result, perRowCallback SelectPerRowCallback) error {
|
||||||
|
if err := c.writeCommandStr(COM_QUERY, command); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.readResultStreaming(false, result, perRowCallback)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Conn) Begin() error {
|
func (c *Conn) Begin() error {
|
||||||
_, err := c.exec("BEGIN")
|
_, err := c.exec("BEGIN")
|
||||||
return errors.Trace(err)
|
return errors.Trace(err)
|
476
vendor/github.com/go-mysql-org/go-mysql/client/pool.go
generated
vendored
Normal file
476
vendor/github.com/go-mysql-org/go-mysql/client/pool.go
generated
vendored
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pingcap/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pool for efficient reuse of connections.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
pool := client.NewPool(log.Debugf, 100, 400, 5, `127.0.0.1:3306`, `username`, `userpwd`, `dbname`)
|
||||||
|
...
|
||||||
|
conn, _ := pool.GetConn(ctx)
|
||||||
|
defer pool.PutConn(conn)
|
||||||
|
conn.Execute/conn.Begin/etc...
|
||||||
|
*/
|
||||||
|
|
||||||
|
type (
|
||||||
|
Timestamp int64
|
||||||
|
|
||||||
|
LogFunc func(format string, args ...interface{})
|
||||||
|
|
||||||
|
Pool struct {
|
||||||
|
logFunc LogFunc
|
||||||
|
minAlive int
|
||||||
|
maxAlive int
|
||||||
|
maxIdle int
|
||||||
|
idleCloseTimeout Timestamp
|
||||||
|
idlePingTimeout Timestamp
|
||||||
|
connect func() (*Conn, error)
|
||||||
|
|
||||||
|
synchro struct {
|
||||||
|
sync.Mutex
|
||||||
|
idleConnections []Connection
|
||||||
|
stats ConnectionStats
|
||||||
|
}
|
||||||
|
|
||||||
|
readyConnection chan Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionStats struct {
|
||||||
|
// Uses internally
|
||||||
|
TotalCount int
|
||||||
|
|
||||||
|
// Only for stats
|
||||||
|
IdleCount int
|
||||||
|
CreatedCount int64
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection struct {
|
||||||
|
conn *Conn
|
||||||
|
lastUseAt Timestamp
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// MaxIdleTimeoutWithoutPing - If the connection has been idle for more than this time,
|
||||||
|
// then ping will be performed before use to check if it alive
|
||||||
|
MaxIdleTimeoutWithoutPing = 10 * time.Second
|
||||||
|
|
||||||
|
// DefaultIdleTimeout - If the connection has been idle for more than this time,
|
||||||
|
// we can close it (but we should remember about Pool.minAlive)
|
||||||
|
DefaultIdleTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
// MaxNewConnectionAtOnce - If we need to create new connections,
|
||||||
|
// then we will create no more than this number of connections at a time.
|
||||||
|
// This restriction will be ignored on pool initialization.
|
||||||
|
MaxNewConnectionAtOnce = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPool initializes new connection pool and uses params: addr, user, password, dbName and options.
|
||||||
|
// minAlive specifies the minimum number of open connections that the pool will try to maintain.
|
||||||
|
// maxAlive specifies the maximum number of open connections
|
||||||
|
// (for internal reasons, may be greater by 1 inside newConnectionProducer).
|
||||||
|
// maxIdle specifies the maximum number of idle connections (see DefaultIdleTimeout).
|
||||||
|
func NewPool(
|
||||||
|
logFunc LogFunc,
|
||||||
|
minAlive int,
|
||||||
|
maxAlive int,
|
||||||
|
maxIdle int,
|
||||||
|
addr string,
|
||||||
|
user string,
|
||||||
|
password string,
|
||||||
|
dbName string,
|
||||||
|
options ...func(conn *Conn),
|
||||||
|
) *Pool {
|
||||||
|
if minAlive > maxAlive {
|
||||||
|
minAlive = maxAlive
|
||||||
|
}
|
||||||
|
if maxIdle > maxAlive {
|
||||||
|
maxIdle = maxAlive
|
||||||
|
}
|
||||||
|
if maxIdle <= minAlive {
|
||||||
|
maxIdle = minAlive
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := &Pool{
|
||||||
|
logFunc: logFunc,
|
||||||
|
minAlive: minAlive,
|
||||||
|
maxAlive: maxAlive,
|
||||||
|
maxIdle: maxIdle,
|
||||||
|
|
||||||
|
idleCloseTimeout: Timestamp(math.Ceil(DefaultIdleTimeout.Seconds())),
|
||||||
|
idlePingTimeout: Timestamp(math.Ceil(MaxIdleTimeoutWithoutPing.Seconds())),
|
||||||
|
|
||||||
|
connect: func() (*Conn, error) {
|
||||||
|
return Connect(addr, user, password, dbName, options...)
|
||||||
|
},
|
||||||
|
|
||||||
|
readyConnection: make(chan Connection),
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.synchro.idleConnections = make([]Connection, 0, pool.maxIdle)
|
||||||
|
|
||||||
|
go pool.newConnectionProducer()
|
||||||
|
|
||||||
|
if pool.minAlive > 0 {
|
||||||
|
pool.logFunc(`Pool: Setup %d new connections (minimal pool size)...`, pool.minAlive)
|
||||||
|
pool.startNewConnections(pool.minAlive)
|
||||||
|
}
|
||||||
|
|
||||||
|
go pool.closeOldIdleConnections()
|
||||||
|
|
||||||
|
return pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) GetStats(stats *ConnectionStats) {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
|
||||||
|
*stats = pool.synchro.stats
|
||||||
|
|
||||||
|
stats.IdleCount = len(pool.synchro.idleConnections)
|
||||||
|
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConn returns connection from the pool or create new
|
||||||
|
func (pool *Pool) GetConn(ctx context.Context) (*Conn, error) {
|
||||||
|
for {
|
||||||
|
connection, err := pool.getConnection(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// For long time idle connections, we do a ping check
|
||||||
|
if delta := pool.nowTs() - connection.lastUseAt; delta > pool.idlePingTimeout {
|
||||||
|
if err := pool.ping(connection.conn); err != nil {
|
||||||
|
pool.closeConn(connection.conn)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection.conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutConn returns working connection back to pool
|
||||||
|
func (pool *Pool) PutConn(conn *Conn) {
|
||||||
|
pool.putConnection(Connection{
|
||||||
|
conn: conn,
|
||||||
|
lastUseAt: pool.nowTs(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropConn closes the connection without any checks
|
||||||
|
func (pool *Pool) DropConn(conn *Conn) {
|
||||||
|
pool.closeConn(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) putConnection(connection Connection) {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
defer pool.synchro.Unlock()
|
||||||
|
|
||||||
|
// If someone is already waiting for a connection, then we return it to him
|
||||||
|
select {
|
||||||
|
case pool.readyConnection <- connection:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nobody needs this connection
|
||||||
|
|
||||||
|
pool.putConnectionUnsafe(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) nowTs() Timestamp {
|
||||||
|
return Timestamp(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) getConnection(ctx context.Context) (Connection, error) {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
|
||||||
|
connection := pool.getIdleConnectionUnsafe()
|
||||||
|
if connection.conn != nil {
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
return connection, nil
|
||||||
|
}
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
// No idle connections are available
|
||||||
|
|
||||||
|
select {
|
||||||
|
case connection := <-pool.readyConnection:
|
||||||
|
return connection, nil
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
return Connection{}, ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) putConnectionUnsafe(connection Connection) {
|
||||||
|
if len(pool.synchro.idleConnections) == cap(pool.synchro.idleConnections) {
|
||||||
|
pool.synchro.stats.TotalCount--
|
||||||
|
_ = connection.conn.Close() // Could it be more effective to close older connections?
|
||||||
|
} else {
|
||||||
|
pool.synchro.idleConnections = append(pool.synchro.idleConnections, connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) newConnectionProducer() {
|
||||||
|
var connection Connection
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for {
|
||||||
|
connection.conn = nil
|
||||||
|
|
||||||
|
pool.synchro.Lock()
|
||||||
|
|
||||||
|
connection = pool.getIdleConnectionUnsafe()
|
||||||
|
if connection.conn == nil {
|
||||||
|
if pool.synchro.stats.TotalCount >= pool.maxAlive {
|
||||||
|
// Can't create more connections
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pool.synchro.stats.TotalCount++ // "Reserving" new connection
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
if connection.conn == nil {
|
||||||
|
connection, err = pool.createNewConnection()
|
||||||
|
if err != nil {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
pool.synchro.stats.TotalCount-- // Bad luck, should try again
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(10+rand.Intn(90)) * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.readyConnection <- connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) createNewConnection() (Connection, error) {
|
||||||
|
var connection Connection
|
||||||
|
var err error
|
||||||
|
|
||||||
|
connection.conn, err = pool.connect()
|
||||||
|
if err != nil {
|
||||||
|
return Connection{}, errors.Errorf(`Could not connect to mysql: %s`, err)
|
||||||
|
}
|
||||||
|
connection.lastUseAt = pool.nowTs()
|
||||||
|
|
||||||
|
pool.synchro.Lock()
|
||||||
|
pool.synchro.stats.CreatedCount++
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
return connection, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) getIdleConnectionUnsafe() Connection {
|
||||||
|
cnt := len(pool.synchro.idleConnections)
|
||||||
|
if cnt == 0 {
|
||||||
|
return Connection{}
|
||||||
|
}
|
||||||
|
|
||||||
|
last := cnt - 1
|
||||||
|
connection := pool.synchro.idleConnections[last]
|
||||||
|
pool.synchro.idleConnections[last].conn = nil
|
||||||
|
pool.synchro.idleConnections = pool.synchro.idleConnections[:last]
|
||||||
|
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) closeOldIdleConnections() {
|
||||||
|
var toPing []Connection
|
||||||
|
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
toPing = pool.getOldIdleConnections(toPing[:0])
|
||||||
|
if len(toPing) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pool.recheckConnections(toPing)
|
||||||
|
|
||||||
|
if !pool.spawnConnectionsIfNeeded() {
|
||||||
|
pool.closeIdleConnectionsIfCan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) getOldIdleConnections(dst []Connection) []Connection {
|
||||||
|
dst = dst[:0]
|
||||||
|
|
||||||
|
pool.synchro.Lock()
|
||||||
|
|
||||||
|
synchro := &pool.synchro
|
||||||
|
|
||||||
|
idleCnt := len(synchro.idleConnections)
|
||||||
|
checkBefore := pool.nowTs() - pool.idlePingTimeout
|
||||||
|
|
||||||
|
for i := idleCnt - 1; i >= 0; i-- {
|
||||||
|
if synchro.idleConnections[i].lastUseAt > checkBefore {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = append(dst, synchro.idleConnections[i])
|
||||||
|
|
||||||
|
last := idleCnt - 1
|
||||||
|
if i < last {
|
||||||
|
// Removing an item from the middle of a slice
|
||||||
|
synchro.idleConnections[i], synchro.idleConnections[last] = synchro.idleConnections[last], synchro.idleConnections[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
synchro.idleConnections[last].conn = nil
|
||||||
|
synchro.idleConnections = synchro.idleConnections[:last]
|
||||||
|
idleCnt--
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) recheckConnections(connections []Connection) {
|
||||||
|
const workerCnt = 2 // Heuristic :)
|
||||||
|
|
||||||
|
queue := make(chan Connection, len(connections))
|
||||||
|
for _, connection := range connections {
|
||||||
|
queue <- connection
|
||||||
|
}
|
||||||
|
close(queue)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(workerCnt)
|
||||||
|
for worker := 0; worker < workerCnt; worker++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for connection := range queue {
|
||||||
|
if err := pool.ping(connection.conn); err != nil {
|
||||||
|
pool.closeConn(connection.conn)
|
||||||
|
} else {
|
||||||
|
pool.putConnection(connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawnConnectionsIfNeeded creates new connections if there are not enough of them and returns true in this case
|
||||||
|
func (pool *Pool) spawnConnectionsIfNeeded() bool {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
totalCount := pool.synchro.stats.TotalCount
|
||||||
|
idleCount := len(pool.synchro.idleConnections)
|
||||||
|
needSpanNew := pool.minAlive - totalCount
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
if needSpanNew <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Не хватает соединений, нужно создать еще
|
||||||
|
|
||||||
|
if needSpanNew > MaxNewConnectionAtOnce {
|
||||||
|
needSpanNew = MaxNewConnectionAtOnce
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.logFunc(`Pool: Setup %d new connections (total: %d idle: %d)...`, needSpanNew, totalCount, idleCount)
|
||||||
|
pool.startNewConnections(needSpanNew)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) closeIdleConnectionsIfCan() {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
|
||||||
|
canCloseCnt := pool.synchro.stats.TotalCount - pool.minAlive
|
||||||
|
canCloseCnt-- // -1 to account for an open but unused connection (pool.readyConnection <- connection in newConnectionProducer)
|
||||||
|
|
||||||
|
idleCnt := len(pool.synchro.idleConnections)
|
||||||
|
|
||||||
|
inFly := pool.synchro.stats.TotalCount - idleCnt
|
||||||
|
|
||||||
|
// We can close no more than 10% connections at a time, but at least 1, if possible
|
||||||
|
idleCanCloseCnt := idleCnt / 10
|
||||||
|
if idleCanCloseCnt == 0 {
|
||||||
|
idleCanCloseCnt = 1
|
||||||
|
}
|
||||||
|
if canCloseCnt > idleCanCloseCnt {
|
||||||
|
canCloseCnt = idleCanCloseCnt
|
||||||
|
}
|
||||||
|
if canCloseCnt <= 0 {
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
closeFromIdx := idleCnt - canCloseCnt
|
||||||
|
if closeFromIdx < 0 {
|
||||||
|
// If there are enough requests in the "flight" now, then we can close all unnecessary
|
||||||
|
closeFromIdx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
toClose := append([]Connection{}, pool.synchro.idleConnections[closeFromIdx:]...)
|
||||||
|
|
||||||
|
for i := closeFromIdx; i < idleCnt; i++ {
|
||||||
|
pool.synchro.idleConnections[i].conn = nil
|
||||||
|
}
|
||||||
|
pool.synchro.idleConnections = pool.synchro.idleConnections[:closeFromIdx]
|
||||||
|
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
pool.logFunc(`Pool: Close %d idle connections (in fly %d)`, len(toClose), inFly)
|
||||||
|
for _, connection := range toClose {
|
||||||
|
pool.closeConn(connection.conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) closeConn(conn *Conn) {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
pool.synchro.stats.TotalCount--
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
|
||||||
|
_ = conn.Close() // Closing is not an instant action, so do it outside the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) startNewConnections(count int) {
|
||||||
|
connections := make([]Connection, 0, count)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
if conn, err := pool.createNewConnection(); err == nil {
|
||||||
|
pool.synchro.Lock()
|
||||||
|
pool.synchro.stats.TotalCount++
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
connections = append(connections, conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.synchro.Lock()
|
||||||
|
for _, connection := range connections {
|
||||||
|
pool.putConnectionUnsafe(connection)
|
||||||
|
}
|
||||||
|
pool.synchro.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pool *Pool) ping(conn *Conn) error {
|
||||||
|
deadline := time.Now().Add(100 * time.Millisecond)
|
||||||
|
_ = conn.SetWriteDeadline(deadline)
|
||||||
|
_ = conn.SetReadDeadline(deadline)
|
||||||
|
err := conn.Ping()
|
||||||
|
if err != nil {
|
||||||
|
pool.logFunc(`Pool: ping query fail: %s`, err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/siddontang/go-mysql/utils"
|
"github.com/go-mysql-org/go-mysql/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) writeCommand(command byte) error {
|
func (c *Conn) writeCommand(command byte) error {
|
@ -7,9 +7,9 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
|
"github.com/go-mysql-org/go-mysql/utils"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go-mysql/utils"
|
|
||||||
"github.com/siddontang/go/hack"
|
"github.com/siddontang/go/hack"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func (c *Conn) handleOKPacket(data []byte) (*Result, error) {
|
|||||||
var n int
|
var n int
|
||||||
var pos = 1
|
var pos = 1
|
||||||
|
|
||||||
r := new(Result)
|
r := &Result{Resultset: &Resultset{}}
|
||||||
|
|
||||||
r.AffectedRows, _, n = LengthEncodedInt(data[pos:])
|
r.AffectedRows, _, n = LengthEncodedInt(data[pos:])
|
||||||
pos += n
|
pos += n
|
||||||
@ -101,6 +101,10 @@ func (c *Conn) handleAuthResult() error {
|
|||||||
}
|
}
|
||||||
c.authPluginName = switchToPlugin
|
c.authPluginName = switchToPlugin
|
||||||
auth, addNull, err := c.genAuthResponse(data)
|
auth, addNull, err := c.genAuthResponse(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err = c.WriteAuthSwitchPacket(auth, addNull); err != nil {
|
if err = c.WriteAuthSwitchPacket(auth, addNull); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -138,7 +142,7 @@ func (c *Conn) handleAuthResult() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.Errorf("invalid packet")
|
return errors.Errorf("invalid packet %x", data[0])
|
||||||
}
|
}
|
||||||
} else if c.authPluginName == AUTH_SHA256_PASSWORD {
|
} else if c.authPluginName == AUTH_SHA256_PASSWORD {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
@ -169,7 +173,6 @@ func (c *Conn) readAuthResult() ([]byte, string, error) {
|
|||||||
// see: https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/
|
// see: https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/
|
||||||
// packet indicator
|
// packet indicator
|
||||||
switch data[0] {
|
switch data[0] {
|
||||||
|
|
||||||
case OK_HEADER:
|
case OK_HEADER:
|
||||||
_, err := c.handleOKPacket(data)
|
_, err := c.handleOKPacket(data)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
@ -230,6 +233,42 @@ func (c *Conn) readResult(binary bool) (*Result, error) {
|
|||||||
return c.readResultset(firstPkgBuf, binary)
|
return c.readResultset(firstPkgBuf, binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) readResultStreaming(binary bool, result *Result, perRowCb SelectPerRowCallback) error {
|
||||||
|
firstPkgBuf, err := c.ReadPacketReuseMem(utils.ByteSliceGet(16)[:0])
|
||||||
|
defer utils.ByteSlicePut(firstPkgBuf)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if firstPkgBuf[0] == OK_HEADER {
|
||||||
|
// https://dev.mysql.com/doc/internals/en/com-query-response.html
|
||||||
|
// 14.6.4.1 COM_QUERY Response
|
||||||
|
// If the number of columns in the resultset is 0, this is a OK_Packet.
|
||||||
|
|
||||||
|
okResult, err := c.handleOKPacket(firstPkgBuf)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Status = okResult.Status
|
||||||
|
result.AffectedRows = okResult.AffectedRows
|
||||||
|
result.InsertId = okResult.InsertId
|
||||||
|
if result.Resultset == nil {
|
||||||
|
result.Resultset = NewResultset(0)
|
||||||
|
} else {
|
||||||
|
result.Reset(0)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else if firstPkgBuf[0] == ERR_HEADER {
|
||||||
|
return c.handleErrorPacket(append([]byte{}, firstPkgBuf...))
|
||||||
|
} else if firstPkgBuf[0] == LocalInFile_HEADER {
|
||||||
|
return ErrMalformPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.readResultsetStreaming(firstPkgBuf, binary, result, perRowCb)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Conn) readResultset(data []byte, binary bool) (*Result, error) {
|
func (c *Conn) readResultset(data []byte, binary bool) (*Result, error) {
|
||||||
// column count
|
// column count
|
||||||
count, _, n := LengthEncodedInt(data)
|
count, _, n := LengthEncodedInt(data)
|
||||||
@ -253,6 +292,31 @@ func (c *Conn) readResultset(data []byte, binary bool) (*Result, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) readResultsetStreaming(data []byte, binary bool, result *Result, perRowCb SelectPerRowCallback) error {
|
||||||
|
columnCount, _, n := LengthEncodedInt(data)
|
||||||
|
|
||||||
|
if n-len(data) != 0 {
|
||||||
|
return ErrMalformPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Resultset == nil {
|
||||||
|
result.Resultset = NewResultset(int(columnCount))
|
||||||
|
} else {
|
||||||
|
// Reuse memory if can
|
||||||
|
result.Reset(int(columnCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.readResultColumns(result); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.readResultRowsStreaming(result, binary, perRowCb); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Conn) readResultColumns(result *Result) (err error) {
|
func (c *Conn) readResultColumns(result *Result) (err error) {
|
||||||
var i int = 0
|
var i int = 0
|
||||||
var data []byte
|
var data []byte
|
||||||
@ -341,3 +405,47 @@ func (c *Conn) readResultRows(result *Result, isBinary bool) (err error) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) readResultRowsStreaming(result *Result, isBinary bool, perRowCb SelectPerRowCallback) (err error) {
|
||||||
|
var (
|
||||||
|
data []byte
|
||||||
|
row []FieldValue
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
data, err = c.ReadPacketReuseMem(data[:0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF Packet
|
||||||
|
if c.isEOFPacket(data) {
|
||||||
|
if c.capability&CLIENT_PROTOCOL_41 > 0 {
|
||||||
|
// result.Warnings = binary.LittleEndian.Uint16(data[1:])
|
||||||
|
// todo add strict_mode, warning will be treat as error
|
||||||
|
result.Status = binary.LittleEndian.Uint16(data[3:])
|
||||||
|
c.status = result.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if data[0] == ERR_HEADER {
|
||||||
|
return c.handleErrorPacket(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse this row
|
||||||
|
row, err = RowData(data).Parse(result.Fields, isBinary, row)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the row to "userland" code
|
||||||
|
err = perRowCb(row)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -5,14 +5,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Stmt struct {
|
type Stmt struct {
|
||||||
conn *Conn
|
conn *Conn
|
||||||
id uint32
|
id uint32
|
||||||
query string
|
|
||||||
|
|
||||||
params int
|
params int
|
||||||
columns int
|
columns int
|
||||||
@ -55,7 +54,7 @@ func (s *Stmt) write(args ...interface{}) error {
|
|||||||
//NULL-bitmap, length: (num-params+7)
|
//NULL-bitmap, length: (num-params+7)
|
||||||
nullBitmap := make([]byte, (paramsNum+7)>>3)
|
nullBitmap := make([]byte, (paramsNum+7)>>3)
|
||||||
|
|
||||||
var length int = int(1 + 4 + 1 + 4 + ((paramsNum + 7) >> 3) + 1 + (paramsNum << 1))
|
length := 1 + 4 + 1 + 4 + ((paramsNum + 7) >> 3) + 1 + (paramsNum << 1)
|
||||||
|
|
||||||
var newParamBoundFlag byte = 0
|
var newParamBoundFlag byte = 0
|
||||||
|
|
||||||
@ -91,11 +90,11 @@ func (s *Stmt) write(args ...interface{}) error {
|
|||||||
case uint16:
|
case uint16:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_SHORT
|
paramTypes[i<<1] = MYSQL_TYPE_SHORT
|
||||||
paramTypes[(i<<1)+1] = 0x80
|
paramTypes[(i<<1)+1] = 0x80
|
||||||
paramValues[i] = Uint16ToBytes(uint16(v))
|
paramValues[i] = Uint16ToBytes(v)
|
||||||
case uint32:
|
case uint32:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_LONG
|
paramTypes[i<<1] = MYSQL_TYPE_LONG
|
||||||
paramTypes[(i<<1)+1] = 0x80
|
paramTypes[(i<<1)+1] = 0x80
|
||||||
paramValues[i] = Uint32ToBytes(uint32(v))
|
paramValues[i] = Uint32ToBytes(v)
|
||||||
case uint:
|
case uint:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_LONGLONG
|
paramTypes[i<<1] = MYSQL_TYPE_LONGLONG
|
||||||
paramTypes[(i<<1)+1] = 0x80
|
paramTypes[(i<<1)+1] = 0x80
|
||||||
@ -103,14 +102,13 @@ func (s *Stmt) write(args ...interface{}) error {
|
|||||||
case uint64:
|
case uint64:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_LONGLONG
|
paramTypes[i<<1] = MYSQL_TYPE_LONGLONG
|
||||||
paramTypes[(i<<1)+1] = 0x80
|
paramTypes[(i<<1)+1] = 0x80
|
||||||
paramValues[i] = Uint64ToBytes(uint64(v))
|
paramValues[i] = Uint64ToBytes(v)
|
||||||
case bool:
|
case bool:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_TINY
|
paramTypes[i<<1] = MYSQL_TYPE_TINY
|
||||||
if v {
|
if v {
|
||||||
paramValues[i] = []byte{1}
|
paramValues[i] = []byte{1}
|
||||||
} else {
|
} else {
|
||||||
paramValues[i] = []byte{0}
|
paramValues[i] = []byte{0}
|
||||||
|
|
||||||
}
|
}
|
||||||
case float32:
|
case float32:
|
||||||
paramTypes[i<<1] = MYSQL_TYPE_FLOAT
|
paramTypes[i<<1] = MYSQL_TYPE_FLOAT
|
File diff suppressed because it is too large
Load Diff
@ -591,7 +591,7 @@ var MySQLErrName = map[uint16]string{
|
|||||||
ER_BINLOG_PURGE_EMFILE: "Too many files opened, please execute the command again",
|
ER_BINLOG_PURGE_EMFILE: "Too many files opened, please execute the command again",
|
||||||
ER_EVENT_CANNOT_CREATE_IN_THE_PAST: "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.",
|
ER_EVENT_CANNOT_CREATE_IN_THE_PAST: "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.",
|
||||||
ER_EVENT_CANNOT_ALTER_IN_THE_PAST: "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was not changed. Specify a time in the future.",
|
ER_EVENT_CANNOT_ALTER_IN_THE_PAST: "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was not changed. Specify a time in the future.",
|
||||||
ER_SLAVE_INCIDENT: "The incident %s occured on the master. Message: %-.64s",
|
ER_SLAVE_INCIDENT: "The incident %s occurred on the master. Message: %-.64s",
|
||||||
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT: "Table has no partition for some existing values",
|
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT: "Table has no partition for some existing values",
|
||||||
ER_BINLOG_UNSAFE_STATEMENT: "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s",
|
ER_BINLOG_UNSAFE_STATEMENT: "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s",
|
||||||
ER_SLAVE_FATAL_ERROR: "Fatal error: %s",
|
ER_SLAVE_FATAL_ERROR: "Fatal error: %s",
|
@ -3,7 +3,7 @@ package mysql
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/siddontang/go-mysql/utils"
|
"github.com/go-mysql-org/go-mysql/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FieldData []byte
|
type FieldData []byte
|
||||||
@ -130,7 +130,7 @@ func (f *Field) Parse(p FieldData) (err error) {
|
|||||||
f.DefaultValue = p[pos:(pos + int(f.DefaultValueLength))]
|
f.DefaultValue = p[pos:(pos + int(f.DefaultValueLength))]
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p FieldData) Parse() (f *Field, err error) {
|
func (p FieldData) Parse() (f *Field, err error) {
|
@ -3,12 +3,12 @@ package mysql
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
"github.com/siddontang/go-log/log"
|
"github.com/siddontang/go-log/log"
|
||||||
"github.com/siddontang/go/hack"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MariadbGTID represent mariadb gtid, [domain ID]-[server-id]-[sequence]
|
// MariadbGTID represent mariadb gtid, [domain ID]-[server-id]-[sequence]
|
||||||
@ -113,15 +113,9 @@ func ParseMariadbGTIDSet(str string) (GTIDSet, error) {
|
|||||||
if str == "" {
|
if str == "" {
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
err := s.Update(str)
|
||||||
sp := strings.Split(str, ",")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
//todo, handle redundant same uuid
|
|
||||||
for i := 0; i < len(sp); i++ {
|
|
||||||
err := s.Update(sp[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Trace(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
@ -147,17 +141,29 @@ func (s *MariadbGTIDSet) AddSet(gtid *MariadbGTID) error {
|
|||||||
|
|
||||||
// Update updates mariadb gtid set
|
// Update updates mariadb gtid set
|
||||||
func (s *MariadbGTIDSet) Update(GTIDStr string) error {
|
func (s *MariadbGTIDSet) Update(GTIDStr string) error {
|
||||||
gtid, err := ParseMariadbGTID(GTIDStr)
|
sp := strings.Split(GTIDStr, ",")
|
||||||
if err != nil {
|
//todo, handle redundant same uuid
|
||||||
return err
|
for i := 0; i < len(sp); i++ {
|
||||||
|
gtid, err := ParseMariadbGTID(sp[i])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
err = s.AddSet(gtid)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
err = s.AddSet(gtid)
|
|
||||||
return errors.Trace(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MariadbGTIDSet) String() string {
|
func (s *MariadbGTIDSet) String() string {
|
||||||
return hack.String(s.Encode())
|
sets := make([]string, 0, len(s.Sets))
|
||||||
|
for _, set := range s.Sets {
|
||||||
|
sets = append(sets, set.String())
|
||||||
|
}
|
||||||
|
sort.Strings(sets)
|
||||||
|
|
||||||
|
return strings.Join(sets, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes mariadb gtid set
|
// Encode encodes mariadb gtid set
|
@ -32,8 +32,10 @@ func parseInterval(str string) (i Interval, err error) {
|
|||||||
i.Stop = i.Start + 1
|
i.Stop = i.Start + 1
|
||||||
case 2:
|
case 2:
|
||||||
i.Start, err = strconv.ParseInt(p[0], 10, 64)
|
i.Start, err = strconv.ParseInt(p[0], 10, 64)
|
||||||
i.Stop, err = strconv.ParseInt(p[1], 10, 64)
|
if err == nil {
|
||||||
i.Stop = i.Stop + 1
|
i.Stop, err = strconv.ParseInt(p[1], 10, 64)
|
||||||
|
i.Stop++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
err = errors.Errorf("invalid interval format, must n[-n]")
|
err = errors.Errorf("invalid interval format, must n[-n]")
|
||||||
}
|
}
|
||||||
@ -230,14 +232,14 @@ func (s *UUIDSet) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *UUIDSet) encode(w io.Writer) {
|
func (s *UUIDSet) encode(w io.Writer) {
|
||||||
w.Write(s.SID.Bytes())
|
_, _ = w.Write(s.SID.Bytes())
|
||||||
n := int64(len(s.Intervals))
|
n := int64(len(s.Intervals))
|
||||||
|
|
||||||
binary.Write(w, binary.LittleEndian, n)
|
_ = binary.Write(w, binary.LittleEndian, n)
|
||||||
|
|
||||||
for _, i := range s.Intervals {
|
for _, i := range s.Intervals {
|
||||||
binary.Write(w, binary.LittleEndian, i.Start)
|
_ = binary.Write(w, binary.LittleEndian, i.Start)
|
||||||
binary.Write(w, binary.LittleEndian, i.Stop)
|
_ = binary.Write(w, binary.LittleEndian, i.Stop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +294,7 @@ func (s *UUIDSet) Decode(data []byte) error {
|
|||||||
func (s *UUIDSet) Clone() *UUIDSet {
|
func (s *UUIDSet) Clone() *UUIDSet {
|
||||||
clone := new(UUIDSet)
|
clone := new(UUIDSet)
|
||||||
|
|
||||||
clone.SID, _ = uuid.FromString(s.SID.String())
|
copy(clone.SID[:], s.SID[:])
|
||||||
clone.Intervals = s.Intervals.Normalize()
|
clone.Intervals = s.Intervals.Normalize()
|
||||||
|
|
||||||
return clone
|
return clone
|
||||||
@ -318,7 +320,6 @@ func ParseMysqlGTIDSet(str string) (GTIDSet, error) {
|
|||||||
} else {
|
} else {
|
||||||
s.AddSet(set)
|
s.AddSet(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
@ -362,13 +363,13 @@ func (s *MysqlGTIDSet) AddSet(set *UUIDSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *MysqlGTIDSet) Update(GTIDStr string) error {
|
func (s *MysqlGTIDSet) Update(GTIDStr string) error {
|
||||||
uuidSet, err := ParseUUIDSet(GTIDStr)
|
gtidSet, err := ParseMysqlGTIDSet(GTIDStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, uuidSet := range gtidSet.(*MysqlGTIDSet).Sets {
|
||||||
s.AddSet(uuidSet)
|
s.AddSet(uuidSet)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,15 +415,28 @@ func (s *MysqlGTIDSet) Equal(o GTIDSet) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MysqlGTIDSet) String() string {
|
func (s *MysqlGTIDSet) String() string {
|
||||||
|
// there is only one element in gtid set
|
||||||
|
if len(s.Sets) == 1 {
|
||||||
|
for _, set := range s.Sets {
|
||||||
|
return set.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort multi set
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
sep := ""
|
sets := make([]string, 0, len(s.Sets))
|
||||||
for _, set := range s.Sets {
|
for _, set := range s.Sets {
|
||||||
|
sets = append(sets, set.String())
|
||||||
|
}
|
||||||
|
sort.Strings(sets)
|
||||||
|
|
||||||
|
sep := ""
|
||||||
|
for _, set := range sets {
|
||||||
buf.WriteString(sep)
|
buf.WriteString(sep)
|
||||||
buf.WriteString(set.String())
|
buf.WriteString(set)
|
||||||
sep = ","
|
sep = ","
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +446,7 @@ func (s *MysqlGTIDSet) String() string {
|
|||||||
func (s *MysqlGTIDSet) Encode() []byte {
|
func (s *MysqlGTIDSet) Encode() []byte {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
binary.Write(&buf, binary.LittleEndian, uint64(len(s.Sets)))
|
_ = binary.Write(&buf, binary.LittleEndian, uint64(len(s.Sets)))
|
||||||
|
|
||||||
for i := range s.Sets {
|
for i := range s.Sets {
|
||||||
s.Sets[i].encode(&buf)
|
s.Sets[i].encode(&buf)
|
@ -20,7 +20,7 @@ func ParseBinaryUint16(data []byte) uint16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ParseBinaryInt24(data []byte) int32 {
|
func ParseBinaryInt24(data []byte) int32 {
|
||||||
u32 := uint32(ParseBinaryUint24(data))
|
u32 := ParseBinaryUint24(data)
|
||||||
if u32&0x00800000 != 0 {
|
if u32&0x00800000 != 0 {
|
||||||
u32 |= 0xFF000000
|
u32 |= 0xFF000000
|
||||||
}
|
}
|
80
vendor/github.com/go-mysql-org/go-mysql/mysql/position.go
generated
vendored
Normal file
80
vendor/github.com/go-mysql-org/go-mysql/mysql/position.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// For binlog filename + position based replication
|
||||||
|
type Position struct {
|
||||||
|
Name string
|
||||||
|
Pos uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Position) Compare(o Position) int {
|
||||||
|
// First compare binlog name
|
||||||
|
nameCmp := CompareBinlogFileName(p.Name, o.Name)
|
||||||
|
if nameCmp != 0 {
|
||||||
|
return nameCmp
|
||||||
|
}
|
||||||
|
// Same binlog file, compare position
|
||||||
|
if p.Pos > o.Pos {
|
||||||
|
return 1
|
||||||
|
} else if p.Pos < o.Pos {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Position) String() string {
|
||||||
|
return fmt.Sprintf("(%s, %d)", p.Name, p.Pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareBinlogFileName(a, b string) int {
|
||||||
|
// sometimes it's convenient to construct a `Position` literal with no `Name`
|
||||||
|
if a == "" && b == "" {
|
||||||
|
return 0
|
||||||
|
} else if a == "" {
|
||||||
|
return -1
|
||||||
|
} else if b == "" {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
splitBinlogName := func(n string) (string, int) {
|
||||||
|
// mysqld appends a numeric extension to the binary log base name to generate binary log file names
|
||||||
|
// ...
|
||||||
|
// If you supply an extension in the log name (for example, --log-bin=base_name.extension),
|
||||||
|
// the extension is silently removed and ignored.
|
||||||
|
// ref: https://dev.mysql.com/doc/refman/8.0/en/binary-log.html
|
||||||
|
i := strings.LastIndexByte(n, '.')
|
||||||
|
if i == -1 {
|
||||||
|
// try keeping backward compatibility
|
||||||
|
return n, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
seq, err := strconv.Atoi(n[i+1:])
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("binlog file %s doesn't contain numeric extension", err))
|
||||||
|
}
|
||||||
|
return n[:i], seq
|
||||||
|
}
|
||||||
|
|
||||||
|
aBase, aSeq := splitBinlogName(a)
|
||||||
|
bBase, bSeq := splitBinlogName(b)
|
||||||
|
|
||||||
|
if aBase > bBase {
|
||||||
|
return 1
|
||||||
|
} else if aBase < bBase {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if aSeq > bSeq {
|
||||||
|
return 1
|
||||||
|
} else if aSeq < bSeq {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
@ -27,9 +27,9 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewResultset(resultsetCount int) *Resultset {
|
func NewResultset(fieldsCount int) *Resultset {
|
||||||
r := resultsetPool.Get().(*Resultset)
|
r := resultsetPool.Get().(*Resultset)
|
||||||
r.reset(resultsetCount)
|
r.Reset(fieldsCount)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ func (r *Resultset) returnToPool() {
|
|||||||
resultsetPool.Put(r)
|
resultsetPool.Put(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resultset) reset(count int) {
|
func (r *Resultset) Reset(fieldsCount int) {
|
||||||
r.RawPkg = r.RawPkg[:0]
|
r.RawPkg = r.RawPkg[:0]
|
||||||
|
|
||||||
r.Fields = r.Fields[:0]
|
r.Fields = r.Fields[:0]
|
||||||
@ -52,14 +52,14 @@ func (r *Resultset) reset(count int) {
|
|||||||
r.FieldNames = make(map[string]int)
|
r.FieldNames = make(map[string]int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if count == 0 {
|
if fieldsCount == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cap(r.Fields) < count {
|
if cap(r.Fields) < fieldsCount {
|
||||||
r.Fields = make([]*Field, count)
|
r.Fields = make([]*Field, fieldsCount)
|
||||||
} else {
|
} else {
|
||||||
r.Fields = r.Fields[:count]
|
r.Fields = r.Fields[:fieldsCount]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ func (r *Resultset) GetUint(row, column int) (uint64, error) {
|
|||||||
case uint32:
|
case uint32:
|
||||||
return uint64(v), nil
|
return uint64(v), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
return uint64(v), nil
|
return v, nil
|
||||||
case float32:
|
case float32:
|
||||||
return uint64(v), nil
|
return uint64(v), nil
|
||||||
case float64:
|
case float64:
|
@ -17,7 +17,7 @@ func formatTextValue(value interface{}) ([]byte, error) {
|
|||||||
case int32:
|
case int32:
|
||||||
return strconv.AppendInt(nil, int64(v), 10), nil
|
return strconv.AppendInt(nil, int64(v), 10), nil
|
||||||
case int64:
|
case int64:
|
||||||
return strconv.AppendInt(nil, int64(v), 10), nil
|
return strconv.AppendInt(nil, v, 10), nil
|
||||||
case int:
|
case int:
|
||||||
return strconv.AppendInt(nil, int64(v), 10), nil
|
return strconv.AppendInt(nil, int64(v), 10), nil
|
||||||
case uint8:
|
case uint8:
|
||||||
@ -27,13 +27,13 @@ func formatTextValue(value interface{}) ([]byte, error) {
|
|||||||
case uint32:
|
case uint32:
|
||||||
return strconv.AppendUint(nil, uint64(v), 10), nil
|
return strconv.AppendUint(nil, uint64(v), 10), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
return strconv.AppendUint(nil, uint64(v), 10), nil
|
return strconv.AppendUint(nil, v, 10), nil
|
||||||
case uint:
|
case uint:
|
||||||
return strconv.AppendUint(nil, uint64(v), 10), nil
|
return strconv.AppendUint(nil, uint64(v), 10), nil
|
||||||
case float32:
|
case float32:
|
||||||
return strconv.AppendFloat(nil, float64(v), 'f', -1, 64), nil
|
return strconv.AppendFloat(nil, float64(v), 'f', -1, 64), nil
|
||||||
case float64:
|
case float64:
|
||||||
return strconv.AppendFloat(nil, float64(v), 'f', -1, 64), nil
|
return strconv.AppendFloat(nil, v, 'f', -1, 64), nil
|
||||||
case []byte:
|
case []byte:
|
||||||
return v, nil
|
return v, nil
|
||||||
case string:
|
case string:
|
||||||
@ -64,7 +64,7 @@ func formatBinaryValue(value interface{}) ([]byte, error) {
|
|||||||
case uint32:
|
case uint32:
|
||||||
return Uint64ToBytes(uint64(v)), nil
|
return Uint64ToBytes(uint64(v)), nil
|
||||||
case uint64:
|
case uint64:
|
||||||
return Uint64ToBytes(uint64(v)), nil
|
return Uint64ToBytes(v), nil
|
||||||
case uint:
|
case uint:
|
||||||
return Uint64ToBytes(uint64(v)), nil
|
return Uint64ToBytes(uint64(v)), nil
|
||||||
case float32:
|
case float32:
|
||||||
@ -146,7 +146,10 @@ func BuildSimpleTextResultset(names []string, values [][]interface{}) (*Resultse
|
|||||||
}
|
}
|
||||||
if r.Fields[j] == nil {
|
if r.Fields[j] == nil {
|
||||||
r.Fields[j] = &Field{Name: hack.Slice(names[j]), Type: typ}
|
r.Fields[j] = &Field{Name: hack.Slice(names[j]), Type: typ}
|
||||||
formatField(r.Fields[j], value)
|
err = formatField(r.Fields[j], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Trace(err)
|
||||||
|
}
|
||||||
} else if typ != r.Fields[j].Type {
|
} else if typ != r.Fields[j].Type {
|
||||||
// we got another type in the same column. in general, we treat it as an error, except
|
// we got another type in the same column. in general, we treat it as an error, except
|
||||||
// the case, when old value was null, and the new one isn't null, so we can update
|
// the case, when old value was null, and the new one isn't null, so we can update
|
||||||
@ -154,7 +157,10 @@ func BuildSimpleTextResultset(names []string, values [][]interface{}) (*Resultse
|
|||||||
oldIsNull, newIsNull := r.Fields[j].Type == MYSQL_TYPE_NULL, typ == MYSQL_TYPE_NULL
|
oldIsNull, newIsNull := r.Fields[j].Type == MYSQL_TYPE_NULL, typ == MYSQL_TYPE_NULL
|
||||||
if oldIsNull && !newIsNull { // old is null, new isn't, update type info.
|
if oldIsNull && !newIsNull { // old is null, new isn't, update type info.
|
||||||
r.Fields[j].Type = typ
|
r.Fields[j].Type = typ
|
||||||
formatField(r.Fields[j], value)
|
err = formatField(r.Fields[j], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Trace(err)
|
||||||
|
}
|
||||||
} else if !oldIsNull && !newIsNull { // different non-null types, that's an error.
|
} else if !oldIsNull && !newIsNull { // different non-null types, that's an error.
|
||||||
return nil, errors.Errorf("row types aren't consistent")
|
return nil, errors.Errorf("row types aren't consistent")
|
||||||
}
|
}
|
@ -3,8 +3,8 @@ package mysql
|
|||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/go-mysql-org/go-mysql/utils"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
"github.com/siddontang/go-mysql/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RowData []byte
|
type RowData []byte
|
@ -114,7 +114,7 @@ func RandomBuf(size int) ([]byte, error) {
|
|||||||
|
|
||||||
// avoid to generate '\0'
|
// avoid to generate '\0'
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
if uint8(b) == 0 {
|
if b == 0 {
|
||||||
buf[i] = '0'
|
buf[i] = '0'
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,9 +13,9 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
|
"github.com/go-mysql-org/go-mysql/utils"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go-mysql/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BufPool struct {
|
type BufPool struct {
|
||||||
@ -134,7 +134,7 @@ func (c *Conn) ReadPacketTo(w io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
length := int(uint32(c.header[0]) | uint32(c.header[1])<<8 | uint32(c.header[2])<<16)
|
length := int(uint32(c.header[0]) | uint32(c.header[1])<<8 | uint32(c.header[2])<<16)
|
||||||
sequence := uint8(c.header[3])
|
sequence := c.header[3]
|
||||||
|
|
||||||
if sequence != c.Sequence {
|
if sequence != c.Sequence {
|
||||||
return errors.Errorf("invalid sequence %d != %d", sequence, c.Sequence)
|
return errors.Errorf("invalid sequence %d != %d", sequence, c.Sequence)
|
@ -7,8 +7,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartBackup: Like mysqlbinlog remote raw backup
|
// StartBackup: Like mysqlbinlog remote raw backup
|
||||||
@ -22,7 +22,9 @@ func (b *BinlogSyncer) StartBackup(backupDir string, p Position, timeout time.Du
|
|||||||
// Force use raw mode
|
// Force use raw mode
|
||||||
b.parser.SetRawMode(true)
|
b.parser.SetRawMode(true)
|
||||||
|
|
||||||
os.MkdirAll(backupDir, 0755)
|
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
s, err := b.StartSync(p)
|
s, err := b.StartSync(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,7 +84,6 @@ func (b *BinlogSyncer) StartBackup(backupDir string, p Position, timeout time.Du
|
|||||||
if _, err = f.Write(BinLogFileHeader); err != nil {
|
if _, err = f.Write(BinLogFileHeader); err != nil {
|
||||||
return errors.Trace(err)
|
return errors.Trace(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, err := f.Write(e.RawData); err != nil {
|
if n, err := f.Write(e.RawData); err != nil {
|
@ -2,9 +2,10 @@ package replication
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
"github.com/siddontang/go-log/log"
|
"github.com/siddontang/go-log/log"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
@ -10,11 +10,11 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-mysql-org/go-mysql/client"
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
"github.com/siddontang/go-log/log"
|
"github.com/siddontang/go-log/log"
|
||||||
"github.com/siddontang/go-mysql/client"
|
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -104,6 +104,10 @@ type BinlogSyncerConfig struct {
|
|||||||
// https://mariadb.com/kb/en/library/com_binlog_dump/
|
// https://mariadb.com/kb/en/library/com_binlog_dump/
|
||||||
// https://mariadb.com/kb/en/library/annotate_rows_event/
|
// https://mariadb.com/kb/en/library/annotate_rows_event/
|
||||||
DumpCommandFlag uint16
|
DumpCommandFlag uint16
|
||||||
|
|
||||||
|
//Option function is used to set outside of BinlogSyncerConfig, between mysql connection and COM_REGISTER_SLAVE
|
||||||
|
//For MariaDB: slave_gtid_ignore_duplicates、skip_replication、slave_until_gtid
|
||||||
|
Option func(*client.Conn) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// BinlogSyncer syncs binlog event from server.
|
// BinlogSyncer syncs binlog event from server.
|
||||||
@ -179,7 +183,10 @@ func (b *BinlogSyncer) close() {
|
|||||||
b.cancel()
|
b.cancel()
|
||||||
|
|
||||||
if b.c != nil {
|
if b.c != nil {
|
||||||
b.c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
err := b.c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf(`could not set read deadline: %s`, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// kill last connection id
|
// kill last connection id
|
||||||
@ -223,18 +230,26 @@ func (b *BinlogSyncer) registerSlave() error {
|
|||||||
return errors.Trace(err)
|
return errors.Trace(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.cfg.Option != nil {
|
||||||
|
if err = b.cfg.Option(b.c); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(b.cfg.Charset) != 0 {
|
if len(b.cfg.Charset) != 0 {
|
||||||
b.c.SetCharset(b.cfg.Charset)
|
if err = b.c.SetCharset(b.cfg.Charset); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//set read timeout
|
//set read timeout
|
||||||
if b.cfg.ReadTimeout > 0 {
|
if b.cfg.ReadTimeout > 0 {
|
||||||
b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
|
_ = b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.cfg.RecvBufferSize > 0 {
|
if b.cfg.RecvBufferSize > 0 {
|
||||||
if tcp, ok := b.c.Conn.Conn.(*net.TCPConn); ok {
|
if tcp, ok := b.c.Conn.Conn.(*net.TCPConn); ok {
|
||||||
tcp.SetReadBuffer(b.cfg.RecvBufferSize)
|
_ = tcp.SetReadBuffer(b.cfg.RecvBufferSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +283,6 @@ func (b *BinlogSyncer) registerSlave() error {
|
|||||||
// if _, err = b.c.Execute(`SET @master_binlog_checksum=@@global.binlog_checksum`); err != nil {
|
// if _, err = b.c.Execute(`SET @master_binlog_checksum=@@global.binlog_checksum`); err != nil {
|
||||||
// return errors.Trace(err)
|
// return errors.Trace(err)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,7 +711,7 @@ func (b *BinlogSyncer) onStream(s *BinlogStreamer) {
|
|||||||
|
|
||||||
//set read timeout
|
//set read timeout
|
||||||
if b.cfg.ReadTimeout > 0 {
|
if b.cfg.ReadTimeout > 0 {
|
||||||
b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
|
_ = b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset retry count on successful packet receieve
|
// Reset retry count on successful packet receieve
|
@ -11,8 +11,9 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
"github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -100,7 +101,7 @@ func (h *EventHeader) Decode(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *EventHeader) Dump(w io.Writer) {
|
func (h *EventHeader) Dump(w io.Writer) {
|
||||||
fmt.Fprintf(w, "=== %s ===\n", EventType(h.EventType))
|
fmt.Fprintf(w, "=== %s ===\n", h.EventType)
|
||||||
fmt.Fprintf(w, "Date: %s\n", time.Unix(int64(h.Timestamp), 0).Format(TimeFormat))
|
fmt.Fprintf(w, "Date: %s\n", time.Unix(int64(h.Timestamp), 0).Format(TimeFormat))
|
||||||
fmt.Fprintf(w, "Log position: %d\n", h.LogPos)
|
fmt.Fprintf(w, "Log position: %d\n", h.LogPos)
|
||||||
fmt.Fprintf(w, "Event size: %d\n", h.EventSize)
|
fmt.Fprintf(w, "Event size: %d\n", h.EventSize)
|
||||||
@ -309,7 +310,7 @@ func (e *QueryEvent) Decode(data []byte) error {
|
|||||||
e.ExecutionTime = binary.LittleEndian.Uint32(data[pos:])
|
e.ExecutionTime = binary.LittleEndian.Uint32(data[pos:])
|
||||||
pos += 4
|
pos += 4
|
||||||
|
|
||||||
schemaLength := uint8(data[pos])
|
schemaLength := data[pos]
|
||||||
pos++
|
pos++
|
||||||
|
|
||||||
e.ErrorCode = binary.LittleEndian.Uint16(data[pos:])
|
e.ErrorCode = binary.LittleEndian.Uint16(data[pos:])
|
||||||
@ -368,7 +369,7 @@ type GTIDEvent struct {
|
|||||||
|
|
||||||
func (e *GTIDEvent) Decode(data []byte) error {
|
func (e *GTIDEvent) Decode(data []byte) error {
|
||||||
pos := 0
|
pos := 0
|
||||||
e.CommitFlag = uint8(data[pos])
|
e.CommitFlag = data[pos]
|
||||||
pos++
|
pos++
|
||||||
e.SID = data[pos : pos+SidLength]
|
e.SID = data[pos : pos+SidLength]
|
||||||
pos += SidLength
|
pos += SidLength
|
||||||
@ -376,7 +377,7 @@ func (e *GTIDEvent) Decode(data []byte) error {
|
|||||||
pos += 8
|
pos += 8
|
||||||
|
|
||||||
if len(data) >= 42 {
|
if len(data) >= 42 {
|
||||||
if uint8(data[pos]) == LogicalTimestampTypeCode {
|
if data[pos] == LogicalTimestampTypeCode {
|
||||||
pos++
|
pos++
|
||||||
e.LastCommitted = int64(binary.LittleEndian.Uint64(data[pos:]))
|
e.LastCommitted = int64(binary.LittleEndian.Uint64(data[pos:]))
|
||||||
pos += PartLogicalTimestampLength
|
pos += PartLogicalTimestampLength
|
||||||
@ -394,11 +395,9 @@ func (e *GTIDEvent) Decode(data []byte) error {
|
|||||||
e.ImmediateCommitTimestamp &= ^(uint64(1) << 55)
|
e.ImmediateCommitTimestamp &= ^(uint64(1) << 55)
|
||||||
e.OriginalCommitTimestamp = FixedLengthInt(data[pos : pos+7])
|
e.OriginalCommitTimestamp = FixedLengthInt(data[pos : pos+7])
|
||||||
pos += 7
|
pos += 7
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise OriginalCommitTimestamp == ImmediateCommitTimestamp
|
// Otherwise OriginalCommitTimestamp == ImmediateCommitTimestamp
|
||||||
e.OriginalCommitTimestamp = e.ImmediateCommitTimestamp
|
e.OriginalCommitTimestamp = e.ImmediateCommitTimestamp
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRANSACTION_LENGTH_MIN_LENGTH = 1
|
// TRANSACTION_LENGTH_MIN_LENGTH = 1
|
||||||
@ -422,13 +421,10 @@ func (e *GTIDEvent) Decode(data []byte) error {
|
|||||||
e.ImmediateServerVersion &= ^(uint32(1) << 31)
|
e.ImmediateServerVersion &= ^(uint32(1) << 31)
|
||||||
e.OriginalServerVersion = binary.LittleEndian.Uint32(data[pos:])
|
e.OriginalServerVersion = binary.LittleEndian.Uint32(data[pos:])
|
||||||
pos += 4
|
pos += 4
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise OriginalServerVersion == ImmediateServerVersion
|
// Otherwise OriginalServerVersion == ImmediateServerVersion
|
||||||
e.OriginalServerVersion = e.ImmediateServerVersion
|
e.OriginalServerVersion = e.ImmediateServerVersion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -510,7 +506,7 @@ func (e *ExecuteLoadQueryEvent) Decode(data []byte) error {
|
|||||||
e.ExecutionTime = binary.LittleEndian.Uint32(data[pos:])
|
e.ExecutionTime = binary.LittleEndian.Uint32(data[pos:])
|
||||||
pos += 4
|
pos += 4
|
||||||
|
|
||||||
e.SchemaLength = uint8(data[pos])
|
e.SchemaLength = data[pos]
|
||||||
pos++
|
pos++
|
||||||
|
|
||||||
e.ErrorCode = binary.LittleEndian.Uint16(data[pos:])
|
e.ErrorCode = binary.LittleEndian.Uint16(data[pos:])
|
||||||
@ -528,7 +524,7 @@ func (e *ExecuteLoadQueryEvent) Decode(data []byte) error {
|
|||||||
e.EndPos = binary.LittleEndian.Uint32(data[pos:])
|
e.EndPos = binary.LittleEndian.Uint32(data[pos:])
|
||||||
pos += 4
|
pos += 4
|
||||||
|
|
||||||
e.DupHandlingFlags = uint8(data[pos])
|
e.DupHandlingFlags = data[pos]
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -601,7 +597,7 @@ func (e *MariadbGTIDEvent) Decode(data []byte) error {
|
|||||||
pos += 8
|
pos += 8
|
||||||
e.GTID.DomainID = binary.LittleEndian.Uint32(data[pos:])
|
e.GTID.DomainID = binary.LittleEndian.Uint32(data[pos:])
|
||||||
pos += 4
|
pos += 4
|
||||||
e.Flags = uint8(data[pos])
|
e.Flags = data[pos]
|
||||||
pos += 1
|
pos += 1
|
||||||
|
|
||||||
if (e.Flags & BINLOG_MARIADB_FL_GROUP_COMMIT_ID) > 0 {
|
if (e.Flags & BINLOG_MARIADB_FL_GROUP_COMMIT_ID) > 0 {
|
@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go/hack"
|
"github.com/siddontang/go/hack"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ func (d *jsonBinaryDecoder) decodeObjectOrArray(data []byte, isSmall bool, isObj
|
|||||||
count := d.decodeCount(data, isSmall)
|
count := d.decodeCount(data, isSmall)
|
||||||
size := d.decodeCount(data[offsetSize:], isSmall)
|
size := d.decodeCount(data[offsetSize:], isSmall)
|
||||||
|
|
||||||
if d.isDataShort(data, int(size)) {
|
if d.isDataShort(data, size) {
|
||||||
// Before MySQL 5.7.22, json type generated column may have invalid value,
|
// Before MySQL 5.7.22, json type generated column may have invalid value,
|
||||||
// bug ref: https://bugs.mysql.com/bug.php?id=88791
|
// bug ref: https://bugs.mysql.com/bug.php?id=88791
|
||||||
// As generated column value is not used in replication, we can just ignore
|
// As generated column value is not used in replication, we can just ignore
|
||||||
@ -452,7 +452,6 @@ func (d *jsonBinaryDecoder) decodeDateTime(data []byte) interface{} {
|
|||||||
frac := v % (1 << 24)
|
frac := v % (1 << 24)
|
||||||
|
|
||||||
return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", year, month, day, hour, minute, second, frac)
|
return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", year, month, day, hour, minute, second, frac)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *jsonBinaryDecoder) decodeCount(data []byte, isSmall bool) int {
|
func (d *jsonBinaryDecoder) decodeCount(data []byte, isSmall bool) int {
|
@ -80,7 +80,7 @@ func (p *BinlogParser) ParseFile(name string, offset int64, onEvent OnEventFunc)
|
|||||||
offset = 4
|
offset = 4
|
||||||
} else if offset > 4 {
|
} else if offset > 4 {
|
||||||
// FORMAT_DESCRIPTION event should be read by default always (despite that fact passed offset may be higher than 4)
|
// FORMAT_DESCRIPTION event should be read by default always (despite that fact passed offset may be higher than 4)
|
||||||
if _, err = f.Seek(4, os.SEEK_SET); err != nil {
|
if _, err = f.Seek(4, io.SeekStart); err != nil {
|
||||||
return errors.Errorf("seek %s to %d error %v", name, offset, err)
|
return errors.Errorf("seek %s to %d error %v", name, offset, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ func (p *BinlogParser) ParseFile(name string, offset int64, onEvent OnEventFunc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = f.Seek(offset, os.SEEK_SET); err != nil {
|
if _, err = f.Seek(offset, io.SeekStart); err != nil {
|
||||||
return errors.Errorf("seek %s to %d error %v", name, offset, err)
|
return errors.Errorf("seek %s to %d error %v", name, offset, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,6 @@ func (p *BinlogParser) parseSingleEvent(r io.Reader, onEvent OnEventFunc) (bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *BinlogParser) ParseReader(r io.Reader, onEvent OnEventFunc) error {
|
func (p *BinlogParser) ParseReader(r io.Reader, onEvent OnEventFunc) error {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if atomic.LoadUint32(&p.stopProcessing) == 1 {
|
if atomic.LoadUint32(&p.stopProcessing) == 1 {
|
||||||
break
|
break
|
@ -12,8 +12,9 @@ import (
|
|||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"github.com/siddontang/go-log/log"
|
"github.com/siddontang/go-log/log"
|
||||||
. "github.com/siddontang/go-mysql/mysql"
|
|
||||||
"github.com/siddontang/go/hack"
|
"github.com/siddontang/go/hack"
|
||||||
|
|
||||||
|
. "github.com/go-mysql-org/go-mysql/mysql"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errMissingTableMapEvent = errors.New("invalid table id, no corresponding table map event")
|
var errMissingTableMapEvent = errors.New("invalid table id, no corresponding table map event")
|
||||||
@ -145,7 +146,7 @@ func (e *TableMapEvent) Decode(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bitmapByteSize(columnCount int) int {
|
func bitmapByteSize(columnCount int) int {
|
||||||
return int(columnCount+7) / 8
|
return (columnCount + 7) / 8
|
||||||
}
|
}
|
||||||
|
|
||||||
// see mysql sql/log_event.h
|
// see mysql sql/log_event.h
|
||||||
@ -238,10 +239,8 @@ func (e *TableMapEvent) decodeMeta(data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *TableMapEvent) decodeOptionalMeta(data []byte) (err error) {
|
func (e *TableMapEvent) decodeOptionalMeta(data []byte) (err error) {
|
||||||
|
|
||||||
pos := 0
|
pos := 0
|
||||||
for pos < len(data) {
|
for pos < len(data) {
|
||||||
|
|
||||||
// optional metadata fields are stored in Type, Length, Value(TLV) format
|
// optional metadata fields are stored in Type, Length, Value(TLV) format
|
||||||
// Type takes 1 byte. Length is a packed integer value. Values takes Length bytes
|
// Type takes 1 byte. Length is a packed integer value. Values takes Length bytes
|
||||||
t := data[pos]
|
t := data[pos]
|
||||||
@ -637,7 +636,6 @@ func (e *TableMapEvent) EnumSetCollationMap() map[int]uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *TableMapEvent) collationMap(includeType func(int) bool, defaultCharset, columnCharset []uint64) map[int]uint64 {
|
func (e *TableMapEvent) collationMap(includeType func(int) bool, defaultCharset, columnCharset []uint64) map[int]uint64 {
|
||||||
|
|
||||||
if len(defaultCharset) != 0 {
|
if len(defaultCharset) != 0 {
|
||||||
defaultCollation := defaultCharset[0]
|
defaultCollation := defaultCharset[0]
|
||||||
|
|
||||||
@ -666,7 +664,6 @@ func (e *TableMapEvent) collationMap(includeType func(int) bool, defaultCharset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(columnCharset) != 0 {
|
if len(columnCharset) != 0 {
|
||||||
|
|
||||||
p := 0
|
p := 0
|
||||||
ret := make(map[int]uint64)
|
ret := make(map[int]uint64)
|
||||||
for i := 0; i < int(e.ColumnCount); i++ {
|
for i := 0; i < int(e.ColumnCount); i++ {
|
||||||
@ -739,7 +736,6 @@ func (e *TableMapEvent) GeometryTypeMap() map[int]uint64 {
|
|||||||
// Table_map_log_event::print_columns in mysql-8.0/sql/log_event.cc and mariadb-10.5/sql/log_event_client.cc
|
// Table_map_log_event::print_columns in mysql-8.0/sql/log_event.cc and mariadb-10.5/sql/log_event_client.cc
|
||||||
|
|
||||||
func (e *TableMapEvent) realType(i int) byte {
|
func (e *TableMapEvent) realType(i int) byte {
|
||||||
|
|
||||||
typ := e.ColumnType[i]
|
typ := e.ColumnType[i]
|
||||||
|
|
||||||
switch typ {
|
switch typ {
|
||||||
@ -757,7 +753,6 @@ func (e *TableMapEvent) realType(i int) byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *TableMapEvent) IsNumericColumn(i int) bool {
|
func (e *TableMapEvent) IsNumericColumn(i int) bool {
|
||||||
|
|
||||||
switch e.realType(i) {
|
switch e.realType(i) {
|
||||||
case MYSQL_TYPE_TINY,
|
case MYSQL_TYPE_TINY,
|
||||||
MYSQL_TYPE_SHORT,
|
MYSQL_TYPE_SHORT,
|
||||||
@ -772,14 +767,12 @@ func (e *TableMapEvent) IsNumericColumn(i int) bool {
|
|||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCharacterColumn returns true if the column type is considered as character type.
|
// IsCharacterColumn returns true if the column type is considered as character type.
|
||||||
// Note that JSON/GEOMETRY types are treated as character type in mariadb.
|
// Note that JSON/GEOMETRY types are treated as character type in mariadb.
|
||||||
// (JSON is an alias for LONGTEXT in mariadb: https://mariadb.com/kb/en/json-data-type/)
|
// (JSON is an alias for LONGTEXT in mariadb: https://mariadb.com/kb/en/json-data-type/)
|
||||||
func (e *TableMapEvent) IsCharacterColumn(i int) bool {
|
func (e *TableMapEvent) IsCharacterColumn(i int) bool {
|
||||||
|
|
||||||
switch e.realType(i) {
|
switch e.realType(i) {
|
||||||
case MYSQL_TYPE_STRING,
|
case MYSQL_TYPE_STRING,
|
||||||
MYSQL_TYPE_VAR_STRING,
|
MYSQL_TYPE_VAR_STRING,
|
||||||
@ -796,7 +789,6 @@ func (e *TableMapEvent) IsCharacterColumn(i int) bool {
|
|||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *TableMapEvent) IsEnumColumn(i int) bool {
|
func (e *TableMapEvent) IsEnumColumn(i int) bool {
|
||||||
@ -846,7 +838,8 @@ type RowsEvent struct {
|
|||||||
ColumnBitmap2 []byte
|
ColumnBitmap2 []byte
|
||||||
|
|
||||||
//rows: invalid: int64, float64, bool, []byte, string
|
//rows: invalid: int64, float64, bool, []byte, string
|
||||||
Rows [][]interface{}
|
Rows [][]interface{}
|
||||||
|
SkippedColumns [][]int
|
||||||
|
|
||||||
parseTime bool
|
parseTime bool
|
||||||
timestampStringLocation *time.Location
|
timestampStringLocation *time.Location
|
||||||
@ -854,7 +847,7 @@ type RowsEvent struct {
|
|||||||
ignoreJSONDecodeErr bool
|
ignoreJSONDecodeErr bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *RowsEvent) Decode(data []byte) error {
|
func (e *RowsEvent) Decode(data []byte) (err2 error) {
|
||||||
pos := 0
|
pos := 0
|
||||||
e.TableID = FixedLengthInt(data[0:e.tableIDSize])
|
e.TableID = FixedLengthInt(data[0:e.tableIDSize])
|
||||||
pos += e.tableIDSize
|
pos += e.tableIDSize
|
||||||
@ -898,7 +891,9 @@ func (e *RowsEvent) Decode(data []byte) error {
|
|||||||
// ... repeat rows until event-end
|
// ... repeat rows until event-end
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
log.Fatalf("parse rows event panic %v, data %q, parsed rows %#v, table map %#v\n%s", r, data, e, e.Table, Pstack())
|
errStr := fmt.Sprintf("parse rows event panic %v, data %q, parsed rows %#v, table map %#v", r, data, e, e.Table)
|
||||||
|
log.Errorf("%s\n%s", errStr, Pstack())
|
||||||
|
err2 = errors.Trace(errors.New(errStr))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -907,6 +902,7 @@ func (e *RowsEvent) Decode(data []byte) error {
|
|||||||
if e.needBitmap2 {
|
if e.needBitmap2 {
|
||||||
rowsLen += e.ColumnCount
|
rowsLen += e.ColumnCount
|
||||||
}
|
}
|
||||||
|
e.SkippedColumns = make([][]int, 0, rowsLen)
|
||||||
e.Rows = make([][]interface{}, 0, rowsLen)
|
e.Rows = make([][]interface{}, 0, rowsLen)
|
||||||
|
|
||||||
for pos < len(data) {
|
for pos < len(data) {
|
||||||
@ -932,6 +928,7 @@ func isBitSet(bitmap []byte, i int) bool {
|
|||||||
|
|
||||||
func (e *RowsEvent) decodeRows(data []byte, table *TableMapEvent, bitmap []byte) (int, error) {
|
func (e *RowsEvent) decodeRows(data []byte, table *TableMapEvent, bitmap []byte) (int, error) {
|
||||||
row := make([]interface{}, e.ColumnCount)
|
row := make([]interface{}, e.ColumnCount)
|
||||||
|
skips := make([]int, 0)
|
||||||
|
|
||||||
pos := 0
|
pos := 0
|
||||||
|
|
||||||
@ -953,6 +950,7 @@ func (e *RowsEvent) decodeRows(data []byte, table *TableMapEvent, bitmap []byte)
|
|||||||
var err error
|
var err error
|
||||||
for i := 0; i < int(e.ColumnCount); i++ {
|
for i := 0; i < int(e.ColumnCount); i++ {
|
||||||
if !isBitSet(bitmap, i) {
|
if !isBitSet(bitmap, i) {
|
||||||
|
skips = append(skips, i)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,6 +971,7 @@ func (e *RowsEvent) decodeRows(data []byte, table *TableMapEvent, bitmap []byte)
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.Rows = append(e.Rows, row)
|
e.Rows = append(e.Rows, row)
|
||||||
|
e.SkippedColumns = append(e.SkippedColumns, skips)
|
||||||
return pos, nil
|
return pos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,7 +1001,7 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16) (v interface{
|
|||||||
|
|
||||||
if b0&0x30 != 0x30 {
|
if b0&0x30 != 0x30 {
|
||||||
length = int(uint16(b1) | (uint16((b0&0x30)^0x30) << 4))
|
length = int(uint16(b1) | (uint16((b0&0x30)^0x30) << 4))
|
||||||
tp = byte(b0 | 0x30)
|
tp = b0 | 0x30
|
||||||
} else {
|
} else {
|
||||||
length = int(meta & 0xFF)
|
length = int(meta & 0xFF)
|
||||||
tp = b0
|
tp = b0
|
||||||
@ -1045,7 +1044,7 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16) (v interface{
|
|||||||
n = int(nbits+7) / 8
|
n = int(nbits+7) / 8
|
||||||
|
|
||||||
//use int64 for bit
|
//use int64 for bit
|
||||||
v, err = decodeBit(data, int(nbits), int(n))
|
v, err = decodeBit(data, int(nbits), n)
|
||||||
case MYSQL_TYPE_TIMESTAMP:
|
case MYSQL_TYPE_TIMESTAMP:
|
||||||
n = 4
|
n = 4
|
||||||
t := binary.LittleEndian.Uint32(data)
|
t := binary.LittleEndian.Uint32(data)
|
||||||
@ -1092,11 +1091,7 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16) (v interface{
|
|||||||
if i32 == 0 {
|
if i32 == 0 {
|
||||||
v = "00:00:00"
|
v = "00:00:00"
|
||||||
} else {
|
} else {
|
||||||
sign := ""
|
v = fmt.Sprintf("%02d:%02d:%02d", i32/10000, (i32%10000)/100, i32%100)
|
||||||
if i32 < 0 {
|
|
||||||
sign = "-"
|
|
||||||
}
|
|
||||||
v = fmt.Sprintf("%s%02d:%02d:%02d", sign, i32/10000, (i32%10000)/100, i32%100)
|
|
||||||
}
|
}
|
||||||
case MYSQL_TYPE_TIME2:
|
case MYSQL_TYPE_TIME2:
|
||||||
v, n, err = decodeTime2(data, meta)
|
v, n, err = decodeTime2(data, meta)
|
||||||
@ -1158,14 +1153,15 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16) (v interface{
|
|||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unsupport type %d in binlog and don't know how to handle", tp)
|
err = fmt.Errorf("unsupport type %d in binlog and don't know how to handle", tp)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
return v, n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeString(data []byte, length int) (v string, n int) {
|
func decodeString(data []byte, length int) (v string, n int) {
|
||||||
if length < 256 {
|
if length < 256 {
|
||||||
length = int(data[0])
|
length = int(data[0])
|
||||||
|
|
||||||
n = int(length) + 1
|
n = length + 1
|
||||||
v = hack.String(data[1:n])
|
v = hack.String(data[1:n])
|
||||||
} else {
|
} else {
|
||||||
length = int(binary.LittleEndian.Uint16(data[0:]))
|
length = int(binary.LittleEndian.Uint16(data[0:]))
|
||||||
@ -1192,9 +1188,9 @@ func decodeDecimalDecompressValue(compIndx int, data []byte, mask uint8) (size i
|
|||||||
|
|
||||||
func decodeDecimal(data []byte, precision int, decimals int, useDecimal bool) (interface{}, int, error) {
|
func decodeDecimal(data []byte, precision int, decimals int, useDecimal bool) (interface{}, int, error) {
|
||||||
//see python mysql replication and https://github.com/jeremycole/mysql_binlog
|
//see python mysql replication and https://github.com/jeremycole/mysql_binlog
|
||||||
integral := (precision - decimals)
|
integral := precision - decimals
|
||||||
uncompIntegral := int(integral / digitsPerInteger)
|
uncompIntegral := integral / digitsPerInteger
|
||||||
uncompFractional := int(decimals / digitsPerInteger)
|
uncompFractional := decimals / digitsPerInteger
|
||||||
compIntegral := integral - (uncompIntegral * digitsPerInteger)
|
compIntegral := integral - (uncompIntegral * digitsPerInteger)
|
||||||
compFractional := decimals - (uncompFractional * digitsPerInteger)
|
compFractional := decimals - (uncompFractional * digitsPerInteger)
|
||||||
|
|
@ -31,6 +31,6 @@ func ByteSlicePut(data []byte) {
|
|||||||
select {
|
select {
|
||||||
case byteSliceChan <- data:
|
case byteSliceChan <- data:
|
||||||
default:
|
default:
|
||||||
byteSlicePool.Put(data)
|
byteSlicePool.Put(data) //nolint:staticcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
129
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
129
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
@ -1,129 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.10.x
|
|
||||||
- 1.11.x
|
|
||||||
- 1.12.x
|
|
||||||
- 1.13.x
|
|
||||||
- master
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf
|
|
||||||
- sudo service mysql restart
|
|
||||||
- .travis/wait_mysql.sh
|
|
||||||
- mysql -e 'create database gotest;'
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- env: DB=MYSQL8
|
|
||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
go: 1.10.x
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- docker pull mysql:8.0
|
|
||||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
|
||||||
mysql:8.0 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
|
||||||
- cp .travis/docker.cnf ~/.my.cnf
|
|
||||||
- .travis/wait_mysql.sh
|
|
||||||
before_script:
|
|
||||||
- export MYSQL_TEST_USER=gotest
|
|
||||||
- export MYSQL_TEST_PASS=secret
|
|
||||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
|
||||||
- export MYSQL_TEST_CONCURRENT=1
|
|
||||||
|
|
||||||
- env: DB=MYSQL57
|
|
||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
go: 1.10.x
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- docker pull mysql:5.7
|
|
||||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
|
||||||
mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
|
||||||
- cp .travis/docker.cnf ~/.my.cnf
|
|
||||||
- .travis/wait_mysql.sh
|
|
||||||
before_script:
|
|
||||||
- export MYSQL_TEST_USER=gotest
|
|
||||||
- export MYSQL_TEST_PASS=secret
|
|
||||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
|
||||||
- export MYSQL_TEST_CONCURRENT=1
|
|
||||||
|
|
||||||
- env: DB=MARIA55
|
|
||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
go: 1.10.x
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- docker pull mariadb:5.5
|
|
||||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
|
||||||
mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
|
||||||
- cp .travis/docker.cnf ~/.my.cnf
|
|
||||||
- .travis/wait_mysql.sh
|
|
||||||
before_script:
|
|
||||||
- export MYSQL_TEST_USER=gotest
|
|
||||||
- export MYSQL_TEST_PASS=secret
|
|
||||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
|
||||||
- export MYSQL_TEST_CONCURRENT=1
|
|
||||||
|
|
||||||
- env: DB=MARIA10_1
|
|
||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
go: 1.10.x
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- docker pull mariadb:10.1
|
|
||||||
- docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
|
|
||||||
mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1
|
|
||||||
- cp .travis/docker.cnf ~/.my.cnf
|
|
||||||
- .travis/wait_mysql.sh
|
|
||||||
before_script:
|
|
||||||
- export MYSQL_TEST_USER=gotest
|
|
||||||
- export MYSQL_TEST_PASS=secret
|
|
||||||
- export MYSQL_TEST_ADDR=127.0.0.1:3307
|
|
||||||
- export MYSQL_TEST_CONCURRENT=1
|
|
||||||
|
|
||||||
- os: osx
|
|
||||||
osx_image: xcode10.1
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- mysql
|
|
||||||
update: true
|
|
||||||
go: 1.12.x
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
before_script:
|
|
||||||
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB\nlocal_infile=1" >> /usr/local/etc/my.cnf
|
|
||||||
- mysql.server start
|
|
||||||
- mysql -uroot -e 'CREATE USER gotest IDENTIFIED BY "secret"'
|
|
||||||
- mysql -uroot -e 'GRANT ALL ON *.* TO gotest'
|
|
||||||
- mysql -uroot -e 'create database gotest;'
|
|
||||||
- export MYSQL_TEST_USER=gotest
|
|
||||||
- export MYSQL_TEST_PASS=secret
|
|
||||||
- export MYSQL_TEST_ADDR=127.0.0.1:3306
|
|
||||||
- export MYSQL_TEST_CONCURRENT=1
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v -covermode=count -coverprofile=coverage.out
|
|
||||||
- go vet ./...
|
|
||||||
- .travis/gofmt.sh
|
|
||||||
after_script:
|
|
||||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
|
|
12
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
12
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
@ -13,11 +13,15 @@
|
|||||||
|
|
||||||
Aaron Hopkins <go-sql-driver at die.net>
|
Aaron Hopkins <go-sql-driver at die.net>
|
||||||
Achille Roussel <achille.roussel at gmail.com>
|
Achille Roussel <achille.roussel at gmail.com>
|
||||||
|
Alex Snast <alexsn at fb.com>
|
||||||
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
|
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
|
||||||
Andrew Reid <andrew.reid at tixtrack.com>
|
Andrew Reid <andrew.reid at tixtrack.com>
|
||||||
|
Animesh Ray <mail.rayanimesh at gmail.com>
|
||||||
Arne Hormann <arnehormann at gmail.com>
|
Arne Hormann <arnehormann at gmail.com>
|
||||||
|
Ariel Mashraki <ariel at mashraki.co.il>
|
||||||
Asta Xie <xiemengjun at gmail.com>
|
Asta Xie <xiemengjun at gmail.com>
|
||||||
Bulat Gaifullin <gaifullinbf at gmail.com>
|
Bulat Gaifullin <gaifullinbf at gmail.com>
|
||||||
|
Caine Jette <jette at alum.mit.edu>
|
||||||
Carlos Nieto <jose.carlos at menteslibres.net>
|
Carlos Nieto <jose.carlos at menteslibres.net>
|
||||||
Chris Moos <chris at tech9computers.com>
|
Chris Moos <chris at tech9computers.com>
|
||||||
Craig Wilson <craiggwilson at gmail.com>
|
Craig Wilson <craiggwilson at gmail.com>
|
||||||
@ -52,6 +56,7 @@ Julien Schmidt <go-sql-driver at julienschmidt.com>
|
|||||||
Justin Li <jli at j-li.net>
|
Justin Li <jli at j-li.net>
|
||||||
Justin Nuß <nuss.justin at gmail.com>
|
Justin Nuß <nuss.justin at gmail.com>
|
||||||
Kamil Dziedzic <kamil at klecza.pl>
|
Kamil Dziedzic <kamil at klecza.pl>
|
||||||
|
Kei Kamikawa <x00.x7f.x86 at gmail.com>
|
||||||
Kevin Malachowski <kevin at chowski.com>
|
Kevin Malachowski <kevin at chowski.com>
|
||||||
Kieron Woodhouse <kieron.woodhouse at infosum.com>
|
Kieron Woodhouse <kieron.woodhouse at infosum.com>
|
||||||
Lennart Rudolph <lrudolph at hmc.edu>
|
Lennart Rudolph <lrudolph at hmc.edu>
|
||||||
@ -74,20 +79,26 @@ Reed Allman <rdallman10 at gmail.com>
|
|||||||
Richard Wilkes <wilkes at me.com>
|
Richard Wilkes <wilkes at me.com>
|
||||||
Robert Russell <robert at rrbrussell.com>
|
Robert Russell <robert at rrbrussell.com>
|
||||||
Runrioter Wung <runrioter at gmail.com>
|
Runrioter Wung <runrioter at gmail.com>
|
||||||
|
Sho Iizuka <sho.i518 at gmail.com>
|
||||||
|
Sho Ikeda <suicaicoca at gmail.com>
|
||||||
Shuode Li <elemount at qq.com>
|
Shuode Li <elemount at qq.com>
|
||||||
Simon J Mudd <sjmudd at pobox.com>
|
Simon J Mudd <sjmudd at pobox.com>
|
||||||
Soroush Pour <me at soroushjp.com>
|
Soroush Pour <me at soroushjp.com>
|
||||||
Stan Putrya <root.vagner at gmail.com>
|
Stan Putrya <root.vagner at gmail.com>
|
||||||
Stanley Gunawan <gunawan.stanley at gmail.com>
|
Stanley Gunawan <gunawan.stanley at gmail.com>
|
||||||
Steven Hartland <steven.hartland at multiplay.co.uk>
|
Steven Hartland <steven.hartland at multiplay.co.uk>
|
||||||
|
Tan Jinhua <312841925 at qq.com>
|
||||||
Thomas Wodarek <wodarekwebpage at gmail.com>
|
Thomas Wodarek <wodarekwebpage at gmail.com>
|
||||||
Tim Ruffles <timruffles at gmail.com>
|
Tim Ruffles <timruffles at gmail.com>
|
||||||
Tom Jenkinson <tom at tjenkinson.me>
|
Tom Jenkinson <tom at tjenkinson.me>
|
||||||
Vladimir Kovpak <cn007b at gmail.com>
|
Vladimir Kovpak <cn007b at gmail.com>
|
||||||
|
Vladyslav Zhelezniak <zhvladi at gmail.com>
|
||||||
Xiangyu Hu <xiangyu.hu at outlook.com>
|
Xiangyu Hu <xiangyu.hu at outlook.com>
|
||||||
Xiaobing Jiang <s7v7nislands at gmail.com>
|
Xiaobing Jiang <s7v7nislands at gmail.com>
|
||||||
Xiuming Chen <cc at cxm.cc>
|
Xiuming Chen <cc at cxm.cc>
|
||||||
|
Xuehong Chan <chanxuehong at gmail.com>
|
||||||
Zhenye Xie <xiezhenye at gmail.com>
|
Zhenye Xie <xiezhenye at gmail.com>
|
||||||
|
Zhixin Wen <john.wenzhixin at gmail.com>
|
||||||
|
|
||||||
# Organizations
|
# Organizations
|
||||||
|
|
||||||
@ -103,3 +114,4 @@ Multiplay Ltd.
|
|||||||
Percona LLC
|
Percona LLC
|
||||||
Pivotal Inc.
|
Pivotal Inc.
|
||||||
Stripe Inc.
|
Stripe Inc.
|
||||||
|
Zendesk Inc.
|
||||||
|
26
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
26
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
@ -1,3 +1,29 @@
|
|||||||
|
## Version 1.6 (2021-04-01)
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190)
|
||||||
|
- `NullTime` is deprecated (#960, #1144)
|
||||||
|
- Reduce allocations when building SET command (#1111)
|
||||||
|
- Performance improvement for time formatting (#1118)
|
||||||
|
- Performance improvement for time parsing (#1098, #1113)
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
- Implement `driver.Validator` interface (#1106, #1174)
|
||||||
|
- Support returning `uint64` from `Valuer` in `ConvertValue` (#1143)
|
||||||
|
- Add `json.RawMessage` for converter and prepared statement (#1059)
|
||||||
|
- Interpolate `json.RawMessage` as `string` (#1058)
|
||||||
|
- Implements `CheckNamedValue` (#1090)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
|
||||||
|
- Stop rounding times (#1121, #1172)
|
||||||
|
- Put zero filler into the SSL handshake packet (#1066)
|
||||||
|
- Fix checking cancelled connections back into the connection pool (#1095)
|
||||||
|
- Fix remove last 0 byte for mysql_old_password when password is empty (#1133)
|
||||||
|
|
||||||
|
|
||||||
## Version 1.5 (2020-01-07)
|
## Version 1.5 (2020-01-07)
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
|
43
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
43
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
@ -35,7 +35,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
|
|||||||
* Supports queries larger than 16MB
|
* Supports queries larger than 16MB
|
||||||
* Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.
|
* Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.
|
||||||
* Intelligent `LONG DATA` handling in prepared statements
|
* Intelligent `LONG DATA` handling in prepared statements
|
||||||
* Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support
|
* Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support
|
||||||
* Optional `time.Time` parsing
|
* Optional `time.Time` parsing
|
||||||
* Optional placeholder interpolation
|
* Optional placeholder interpolation
|
||||||
|
|
||||||
@ -56,15 +56,37 @@ Make sure [Git is installed](https://git-scm.com/downloads) on your machine and
|
|||||||
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.
|
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.
|
||||||
|
|
||||||
Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
|
Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "database/sql"
|
import (
|
||||||
import _ "github.com/go-sql-driver/mysql"
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
db, err := sql.Open("mysql", "user:password@/dbname")
|
db, err := sql.Open("mysql", "user:password@/dbname")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// See "Important settings" section.
|
||||||
|
db.SetConnMaxLifetime(time.Minute * 3)
|
||||||
|
db.SetMaxOpenConns(10)
|
||||||
|
db.SetMaxIdleConns(10)
|
||||||
```
|
```
|
||||||
|
|
||||||
[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples").
|
[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples").
|
||||||
|
|
||||||
|
### Important settings
|
||||||
|
|
||||||
|
`db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too.
|
||||||
|
|
||||||
|
`db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server.
|
||||||
|
|
||||||
|
`db.SetMaxIdleConns()` is recommended to be set same to (or greater than) `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed very frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15.
|
||||||
|
|
||||||
|
|
||||||
### DSN (Data Source Name)
|
### DSN (Data Source Name)
|
||||||
|
|
||||||
@ -122,7 +144,7 @@ Valid Values: true, false
|
|||||||
Default: false
|
Default: false
|
||||||
```
|
```
|
||||||
|
|
||||||
`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files.
|
`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files.
|
||||||
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
|
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
|
||||||
|
|
||||||
##### `allowCleartextPasswords`
|
##### `allowCleartextPasswords`
|
||||||
@ -133,7 +155,7 @@ Valid Values: true, false
|
|||||||
Default: false
|
Default: false
|
||||||
```
|
```
|
||||||
|
|
||||||
`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
|
`allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
|
||||||
|
|
||||||
##### `allowNativePasswords`
|
##### `allowNativePasswords`
|
||||||
|
|
||||||
@ -230,7 +252,7 @@ Default: false
|
|||||||
|
|
||||||
If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`.
|
If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`.
|
||||||
|
|
||||||
*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are blacklisted as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*
|
*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*
|
||||||
|
|
||||||
##### `loc`
|
##### `loc`
|
||||||
|
|
||||||
@ -376,7 +398,7 @@ Rules:
|
|||||||
Examples:
|
Examples:
|
||||||
* `autocommit=1`: `SET autocommit=1`
|
* `autocommit=1`: `SET autocommit=1`
|
||||||
* [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`
|
* [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`
|
||||||
* [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'`
|
* [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'`
|
||||||
|
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
@ -445,7 +467,7 @@ For this feature you need direct access to the package. Therefore you must chang
|
|||||||
import "github.com/go-sql-driver/mysql"
|
import "github.com/go-sql-driver/mysql"
|
||||||
```
|
```
|
||||||
|
|
||||||
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
|
Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
|
||||||
|
|
||||||
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
|
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
|
||||||
|
|
||||||
@ -459,8 +481,6 @@ However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` v
|
|||||||
|
|
||||||
**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
|
**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
|
||||||
|
|
||||||
Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.
|
|
||||||
|
|
||||||
|
|
||||||
### Unicode support
|
### Unicode support
|
||||||
Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default.
|
Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default.
|
||||||
@ -477,7 +497,7 @@ To run the driver tests you may need to adjust the configuration. See the [Testi
|
|||||||
Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated.
|
Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated.
|
||||||
If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).
|
If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).
|
||||||
|
|
||||||
See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details.
|
See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details.
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
@ -498,4 +518,3 @@ Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you
|
|||||||
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
|
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
|
||||||
|
|
||||||
![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
|
![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
|
||||||
|
|
||||||
|
13
vendor/github.com/go-sql-driver/mysql/auth.go
generated
vendored
13
vendor/github.com/go-sql-driver/mysql/auth.go
generated
vendored
@ -15,6 +15,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -136,10 +137,6 @@ func pwHash(password []byte) (result [2]uint32) {
|
|||||||
|
|
||||||
// Hash password using insecure pre 4.1 method
|
// Hash password using insecure pre 4.1 method
|
||||||
func scrambleOldPassword(scramble []byte, password string) []byte {
|
func scrambleOldPassword(scramble []byte, password string) []byte {
|
||||||
if len(password) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scramble = scramble[:8]
|
scramble = scramble[:8]
|
||||||
|
|
||||||
hashPw := pwHash([]byte(password))
|
hashPw := pwHash([]byte(password))
|
||||||
@ -247,6 +244,9 @@ func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
|
|||||||
if !mc.cfg.AllowOldPasswords {
|
if !mc.cfg.AllowOldPasswords {
|
||||||
return nil, ErrOldPassword
|
return nil, ErrOldPassword
|
||||||
}
|
}
|
||||||
|
if len(mc.cfg.Passwd) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
// Note: there are edge cases where this should work but doesn't;
|
// Note: there are edge cases where this should work but doesn't;
|
||||||
// this is currently "wontfix":
|
// this is currently "wontfix":
|
||||||
// https://github.com/go-sql-driver/mysql/issues/184
|
// https://github.com/go-sql-driver/mysql/issues/184
|
||||||
@ -372,7 +372,10 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(data[1:])
|
block, rest := pem.Decode(data[1:])
|
||||||
|
if block == nil {
|
||||||
|
return fmt.Errorf("No Pem data found, data: %s", rest)
|
||||||
|
}
|
||||||
pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
|
pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
2
vendor/github.com/go-sql-driver/mysql/collations.go
generated
vendored
2
vendor/github.com/go-sql-driver/mysql/collations.go
generated
vendored
@ -247,7 +247,7 @@ var collations = map[string]byte{
|
|||||||
"utf8mb4_0900_ai_ci": 255,
|
"utf8mb4_0900_ai_ci": 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A blacklist of collations which is unsafe to interpolate parameters.
|
// A denylist of collations which is unsafe to interpolate parameters.
|
||||||
// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes.
|
// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes.
|
||||||
var unsafeCollations = map[string]bool{
|
var unsafeCollations = map[string]bool{
|
||||||
"big5_chinese_ci": true,
|
"big5_chinese_ci": true,
|
||||||
|
85
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
85
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
@ -12,6 +12,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -46,9 +47,10 @@ type mysqlConn struct {
|
|||||||
|
|
||||||
// Handles parameters set in DSN after the connection is established
|
// Handles parameters set in DSN after the connection is established
|
||||||
func (mc *mysqlConn) handleParams() (err error) {
|
func (mc *mysqlConn) handleParams() (err error) {
|
||||||
|
var cmdSet strings.Builder
|
||||||
for param, val := range mc.cfg.Params {
|
for param, val := range mc.cfg.Params {
|
||||||
switch param {
|
switch param {
|
||||||
// Charset
|
// Charset: character_set_connection, character_set_client, character_set_results
|
||||||
case "charset":
|
case "charset":
|
||||||
charsets := strings.Split(val, ",")
|
charsets := strings.Split(val, ",")
|
||||||
for i := range charsets {
|
for i := range charsets {
|
||||||
@ -62,12 +64,25 @@ func (mc *mysqlConn) handleParams() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// System Vars
|
// Other system vars accumulated in a single SET command
|
||||||
default:
|
default:
|
||||||
err = mc.exec("SET " + param + "=" + val + "")
|
if cmdSet.Len() == 0 {
|
||||||
if err != nil {
|
// Heuristic: 29 chars for each other key=value to reduce reallocations
|
||||||
return
|
cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1))
|
||||||
|
cmdSet.WriteString("SET ")
|
||||||
|
} else {
|
||||||
|
cmdSet.WriteByte(',')
|
||||||
}
|
}
|
||||||
|
cmdSet.WriteString(param)
|
||||||
|
cmdSet.WriteByte('=')
|
||||||
|
cmdSet.WriteString(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmdSet.Len() > 0 {
|
||||||
|
err = mc.exec(cmdSet.String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,47 +245,21 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
|||||||
if v.IsZero() {
|
if v.IsZero() {
|
||||||
buf = append(buf, "'0000-00-00'"...)
|
buf = append(buf, "'0000-00-00'"...)
|
||||||
} else {
|
} else {
|
||||||
v := v.In(mc.cfg.Loc)
|
buf = append(buf, '\'')
|
||||||
v = v.Add(time.Nanosecond * 500) // To round under microsecond
|
buf, err = appendDateTime(buf, v.In(mc.cfg.Loc))
|
||||||
year := v.Year()
|
if err != nil {
|
||||||
year100 := year / 100
|
return "", err
|
||||||
year1 := year % 100
|
|
||||||
month := v.Month()
|
|
||||||
day := v.Day()
|
|
||||||
hour := v.Hour()
|
|
||||||
minute := v.Minute()
|
|
||||||
second := v.Second()
|
|
||||||
micro := v.Nanosecond() / 1000
|
|
||||||
|
|
||||||
buf = append(buf, []byte{
|
|
||||||
'\'',
|
|
||||||
digits10[year100], digits01[year100],
|
|
||||||
digits10[year1], digits01[year1],
|
|
||||||
'-',
|
|
||||||
digits10[month], digits01[month],
|
|
||||||
'-',
|
|
||||||
digits10[day], digits01[day],
|
|
||||||
' ',
|
|
||||||
digits10[hour], digits01[hour],
|
|
||||||
':',
|
|
||||||
digits10[minute], digits01[minute],
|
|
||||||
':',
|
|
||||||
digits10[second], digits01[second],
|
|
||||||
}...)
|
|
||||||
|
|
||||||
if micro != 0 {
|
|
||||||
micro10000 := micro / 10000
|
|
||||||
micro100 := micro / 100 % 100
|
|
||||||
micro1 := micro % 100
|
|
||||||
buf = append(buf, []byte{
|
|
||||||
'.',
|
|
||||||
digits10[micro10000], digits01[micro10000],
|
|
||||||
digits10[micro100], digits01[micro100],
|
|
||||||
digits10[micro1], digits01[micro1],
|
|
||||||
}...)
|
|
||||||
}
|
}
|
||||||
buf = append(buf, '\'')
|
buf = append(buf, '\'')
|
||||||
}
|
}
|
||||||
|
case json.RawMessage:
|
||||||
|
buf = append(buf, '\'')
|
||||||
|
if mc.status&statusNoBackslashEscapes == 0 {
|
||||||
|
buf = escapeBytesBackslash(buf, v)
|
||||||
|
} else {
|
||||||
|
buf = escapeBytesQuotes(buf, v)
|
||||||
|
}
|
||||||
|
buf = append(buf, '\'')
|
||||||
case []byte:
|
case []byte:
|
||||||
if v == nil {
|
if v == nil {
|
||||||
buf = append(buf, "NULL"...)
|
buf = append(buf, "NULL"...)
|
||||||
@ -480,6 +469,10 @@ func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
// BeginTx implements driver.ConnBeginTx interface
|
// BeginTx implements driver.ConnBeginTx interface
|
||||||
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||||
|
if mc.closed.IsSet() {
|
||||||
|
return nil, driver.ErrBadConn
|
||||||
|
}
|
||||||
|
|
||||||
if err := mc.watchCancel(ctx); err != nil {
|
if err := mc.watchCancel(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -649,3 +642,9 @@ func (mc *mysqlConn) ResetSession(ctx context.Context) error {
|
|||||||
mc.reset = true
|
mc.reset = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsValid implements driver.Validator interface
|
||||||
|
// (From Go 1.15)
|
||||||
|
func (mc *mysqlConn) IsValid() bool {
|
||||||
|
return !mc.closed.IsSet()
|
||||||
|
}
|
||||||
|
2
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
2
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
@ -375,7 +375,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
|||||||
|
|
||||||
// cfg params
|
// cfg params
|
||||||
switch value := param[1]; param[0] {
|
switch value := param[1]; param[0] {
|
||||||
// Disable INFILE whitelist / enable all files
|
// Disable INFILE allowlist / enable all files
|
||||||
case "allowAllFiles":
|
case "allowAllFiles":
|
||||||
var isBool bool
|
var isBool bool
|
||||||
cfg.AllowAllFiles, isBool = readBool(value)
|
cfg.AllowAllFiles, isBool = readBool(value)
|
||||||
|
2
vendor/github.com/go-sql-driver/mysql/fields.go
generated
vendored
2
vendor/github.com/go-sql-driver/mysql/fields.go
generated
vendored
@ -106,7 +106,7 @@ var (
|
|||||||
scanTypeInt64 = reflect.TypeOf(int64(0))
|
scanTypeInt64 = reflect.TypeOf(int64(0))
|
||||||
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
|
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
|
||||||
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
|
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
|
||||||
scanTypeNullTime = reflect.TypeOf(NullTime{})
|
scanTypeNullTime = reflect.TypeOf(nullTime{})
|
||||||
scanTypeUint8 = reflect.TypeOf(uint8(0))
|
scanTypeUint8 = reflect.TypeOf(uint8(0))
|
||||||
scanTypeUint16 = reflect.TypeOf(uint16(0))
|
scanTypeUint16 = reflect.TypeOf(uint16(0))
|
||||||
scanTypeUint32 = reflect.TypeOf(uint32(0))
|
scanTypeUint32 = reflect.TypeOf(uint32(0))
|
||||||
|
24
vendor/github.com/go-sql-driver/mysql/fuzz.go
generated
vendored
Normal file
24
vendor/github.com/go-sql-driver/mysql/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
|
||||||
|
//
|
||||||
|
// Copyright 2020 The Go-MySQL-Driver Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Fuzz(data []byte) int {
|
||||||
|
db, err := sql.Open("mysql", string(data))
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
db.Close()
|
||||||
|
return 1
|
||||||
|
}
|
4
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
4
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
@ -23,7 +23,7 @@ var (
|
|||||||
readerRegisterLock sync.RWMutex
|
readerRegisterLock sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterLocalFile adds the given file to the file whitelist,
|
// RegisterLocalFile adds the given file to the file allowlist,
|
||||||
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
|
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
|
||||||
// Alternatively you can allow the use of all local files with
|
// Alternatively you can allow the use of all local files with
|
||||||
// the DSN parameter 'allowAllFiles=true'
|
// the DSN parameter 'allowAllFiles=true'
|
||||||
@ -45,7 +45,7 @@ func RegisterLocalFile(filePath string) {
|
|||||||
fileRegisterLock.Unlock()
|
fileRegisterLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeregisterLocalFile removes the given filepath from the whitelist.
|
// DeregisterLocalFile removes the given filepath from the allowlist.
|
||||||
func DeregisterLocalFile(filePath string) {
|
func DeregisterLocalFile(filePath string) {
|
||||||
fileRegisterLock.Lock()
|
fileRegisterLock.Lock()
|
||||||
delete(fileRegister, strings.Trim(filePath, `"`))
|
delete(fileRegister, strings.Trim(filePath, `"`))
|
||||||
|
4
vendor/github.com/go-sql-driver/mysql/nulltime.go
generated
vendored
4
vendor/github.com/go-sql-driver/mysql/nulltime.go
generated
vendored
@ -28,11 +28,11 @@ func (nt *NullTime) Scan(value interface{}) (err error) {
|
|||||||
nt.Time, nt.Valid = v, true
|
nt.Time, nt.Valid = v, true
|
||||||
return
|
return
|
||||||
case []byte:
|
case []byte:
|
||||||
nt.Time, err = parseDateTime(string(v), time.UTC)
|
nt.Time, err = parseDateTime(v, time.UTC)
|
||||||
nt.Valid = (err == nil)
|
nt.Valid = (err == nil)
|
||||||
return
|
return
|
||||||
case string:
|
case string:
|
||||||
nt.Time, err = parseDateTime(v, time.UTC)
|
nt.Time, err = parseDateTime([]byte(v), time.UTC)
|
||||||
nt.Valid = (err == nil)
|
nt.Valid = (err == nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
9
vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
generated
vendored
9
vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
generated
vendored
@ -28,4 +28,13 @@ import (
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// This NullTime implementation is not driver-specific
|
// This NullTime implementation is not driver-specific
|
||||||
|
//
|
||||||
|
// Deprecated: NullTime doesn't honor the loc DSN parameter.
|
||||||
|
// NullTime.Scan interprets a time as UTC, not the loc DSN parameter.
|
||||||
|
// Use sql.NullTime instead.
|
||||||
type NullTime sql.NullTime
|
type NullTime sql.NullTime
|
||||||
|
|
||||||
|
// for internal use.
|
||||||
|
// the mysql package uses sql.NullTime if it is available.
|
||||||
|
// if not, the package uses mysql.NullTime.
|
||||||
|
type nullTime = sql.NullTime // sql.NullTime is available
|
||||||
|
5
vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
generated
vendored
5
vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
generated
vendored
@ -32,3 +32,8 @@ type NullTime struct {
|
|||||||
Time time.Time
|
Time time.Time
|
||||||
Valid bool // Valid is true if Time is not NULL
|
Valid bool // Valid is true if Time is not NULL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for internal use.
|
||||||
|
// the mysql package uses sql.NullTime if it is available.
|
||||||
|
// if not, the package uses mysql.NullTime.
|
||||||
|
type nullTime = NullTime // sql.NullTime is not available
|
||||||
|
23
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
23
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -348,6 +349,12 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
|||||||
return errors.New("unknown collation")
|
return errors.New("unknown collation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filler [23 bytes] (all 0x00)
|
||||||
|
pos := 13
|
||||||
|
for ; pos < 13+23; pos++ {
|
||||||
|
data[pos] = 0
|
||||||
|
}
|
||||||
|
|
||||||
// SSL Connection Request Packet
|
// SSL Connection Request Packet
|
||||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
|
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
|
||||||
if mc.cfg.tls != nil {
|
if mc.cfg.tls != nil {
|
||||||
@ -366,12 +373,6 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
|||||||
mc.buf.nc = tlsConn
|
mc.buf.nc = tlsConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filler [23 bytes] (all 0x00)
|
|
||||||
pos := 13
|
|
||||||
for ; pos < 13+23; pos++ {
|
|
||||||
data[pos] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// User [null terminated string]
|
// User [null terminated string]
|
||||||
if len(mc.cfg.User) > 0 {
|
if len(mc.cfg.User) > 0 {
|
||||||
pos += copy(data[pos:], mc.cfg.User)
|
pos += copy(data[pos:], mc.cfg.User)
|
||||||
@ -777,7 +778,7 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
|||||||
case fieldTypeTimestamp, fieldTypeDateTime,
|
case fieldTypeTimestamp, fieldTypeDateTime,
|
||||||
fieldTypeDate, fieldTypeNewDate:
|
fieldTypeDate, fieldTypeNewDate:
|
||||||
dest[i], err = parseDateTime(
|
dest[i], err = parseDateTime(
|
||||||
string(dest[i].([]byte)),
|
dest[i].([]byte),
|
||||||
mc.cfg.Loc,
|
mc.cfg.Loc,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1003,6 +1004,9 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v, ok := arg.(json.RawMessage); ok {
|
||||||
|
arg = []byte(v)
|
||||||
|
}
|
||||||
// cache types and values
|
// cache types and values
|
||||||
switch v := arg.(type) {
|
switch v := arg.(type) {
|
||||||
case int64:
|
case int64:
|
||||||
@ -1112,7 +1116,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|||||||
if v.IsZero() {
|
if v.IsZero() {
|
||||||
b = append(b, "0000-00-00"...)
|
b = append(b, "0000-00-00"...)
|
||||||
} else {
|
} else {
|
||||||
b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
|
b, err = appendDateTime(b, v.In(mc.cfg.Loc))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paramValues = appendLengthEncodedInteger(paramValues,
|
paramValues = appendLengthEncodedInteger(paramValues,
|
||||||
|
30
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
30
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
@ -10,6 +10,7 @@ package mysql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -43,6 +44,11 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
|
|||||||
return converter{}
|
return converter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
|
||||||
|
nv.Value, err = converter{}.ConvertValue(nv.Value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
|
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||||
if stmt.mc.closed.IsSet() {
|
if stmt.mc.closed.IsSet() {
|
||||||
errLog.Print(ErrInvalidConn)
|
errLog.Print(ErrInvalidConn)
|
||||||
@ -129,6 +135,8 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
|
|||||||
return rows, err
|
return rows, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jsonType = reflect.TypeOf(json.RawMessage{})
|
||||||
|
|
||||||
type converter struct{}
|
type converter struct{}
|
||||||
|
|
||||||
// ConvertValue mirrors the reference/default converter in database/sql/driver
|
// ConvertValue mirrors the reference/default converter in database/sql/driver
|
||||||
@ -146,12 +154,17 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !driver.IsValue(sv) {
|
if driver.IsValue(sv) {
|
||||||
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
|
return sv, nil
|
||||||
}
|
}
|
||||||
return sv, nil
|
// A value returend from the Valuer interface can be "a type handled by
|
||||||
|
// a database driver's NamedValueChecker interface" so we should accept
|
||||||
|
// uint64 here as well.
|
||||||
|
if u, ok := sv.(uint64); ok {
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
|
||||||
}
|
}
|
||||||
|
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
switch rv.Kind() {
|
switch rv.Kind() {
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
@ -170,11 +183,14 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
|
|||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return rv.Bool(), nil
|
return rv.Bool(), nil
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
ek := rv.Type().Elem().Kind()
|
switch t := rv.Type(); {
|
||||||
if ek == reflect.Uint8 {
|
case t == jsonType:
|
||||||
|
return v, nil
|
||||||
|
case t.Elem().Kind() == reflect.Uint8:
|
||||||
return rv.Bytes(), nil
|
return rv.Bytes(), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind())
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
|
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return rv.String(), nil
|
return rv.String(), nil
|
||||||
}
|
}
|
||||||
|
195
vendor/github.com/go-sql-driver/mysql/utils.go
generated
vendored
195
vendor/github.com/go-sql-driver/mysql/utils.go
generated
vendored
@ -106,27 +106,136 @@ func readBool(input string) (value bool, valid bool) {
|
|||||||
* Time related utils *
|
* Time related utils *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
func parseDateTime(str string, loc *time.Location) (t time.Time, err error) {
|
func parseDateTime(b []byte, loc *time.Location) (time.Time, error) {
|
||||||
base := "0000-00-00 00:00:00.0000000"
|
const base = "0000-00-00 00:00:00.000000"
|
||||||
switch len(str) {
|
switch len(b) {
|
||||||
case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
|
case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
|
||||||
if str == base[:len(str)] {
|
if string(b) == base[:len(b)] {
|
||||||
return
|
return time.Time{}, nil
|
||||||
}
|
}
|
||||||
t, err = time.Parse(timeFormat[:len(str)], str)
|
|
||||||
|
year, err := parseByteYear(b)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if year <= 0 {
|
||||||
|
year = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[4] != '-' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4])
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := parseByte2Digits(b[5], b[6])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if m <= 0 {
|
||||||
|
m = 1
|
||||||
|
}
|
||||||
|
month := time.Month(m)
|
||||||
|
|
||||||
|
if b[7] != '-' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7])
|
||||||
|
}
|
||||||
|
|
||||||
|
day, err := parseByte2Digits(b[8], b[9])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if day <= 0 {
|
||||||
|
day = 1
|
||||||
|
}
|
||||||
|
if len(b) == 10 {
|
||||||
|
return time.Date(year, month, day, 0, 0, 0, 0, loc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[10] != ' ' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10])
|
||||||
|
}
|
||||||
|
|
||||||
|
hour, err := parseByte2Digits(b[11], b[12])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if b[13] != ':' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13])
|
||||||
|
}
|
||||||
|
|
||||||
|
min, err := parseByte2Digits(b[14], b[15])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if b[16] != ':' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16])
|
||||||
|
}
|
||||||
|
|
||||||
|
sec, err := parseByte2Digits(b[17], b[18])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if len(b) == 19 {
|
||||||
|
return time.Date(year, month, day, hour, min, sec, 0, loc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[19] != '.' {
|
||||||
|
return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19])
|
||||||
|
}
|
||||||
|
nsec, err := parseByteNanoSec(b[20:])
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
return time.Date(year, month, day, hour, min, sec, nsec, loc), nil
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("invalid time string: %s", str)
|
return time.Time{}, fmt.Errorf("invalid time bytes: %s", b)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adjust location
|
func parseByteYear(b []byte) (int, error) {
|
||||||
if err == nil && loc != time.UTC {
|
year, n := 0, 1000
|
||||||
y, mo, d := t.Date()
|
for i := 0; i < 4; i++ {
|
||||||
h, mi, s := t.Clock()
|
v, err := bToi(b[i])
|
||||||
t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
year += v * n
|
||||||
|
n = n / 10
|
||||||
}
|
}
|
||||||
|
return year, nil
|
||||||
|
}
|
||||||
|
|
||||||
return
|
func parseByte2Digits(b1, b2 byte) (int, error) {
|
||||||
|
d1, err := bToi(b1)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d2, err := bToi(b2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return d1*10 + d2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseByteNanoSec(b []byte) (int, error) {
|
||||||
|
ns, digit := 0, 100000 // max is 6-digits
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
v, err := bToi(b[i])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
ns += v * digit
|
||||||
|
digit /= 10
|
||||||
|
}
|
||||||
|
// nanoseconds has 10-digits. (needs to scale digits)
|
||||||
|
// 10 - 6 = 4, so we have to multiple 1000.
|
||||||
|
return ns * 1000, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bToi(b byte) (int, error) {
|
||||||
|
if b < '0' || b > '9' {
|
||||||
|
return 0, errors.New("not [0-9]")
|
||||||
|
}
|
||||||
|
return int(b - '0'), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
|
func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
|
||||||
@ -167,6 +276,64 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
|
|||||||
return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
|
return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendDateTime(buf []byte, t time.Time) ([]byte, error) {
|
||||||
|
year, month, day := t.Date()
|
||||||
|
hour, min, sec := t.Clock()
|
||||||
|
nsec := t.Nanosecond()
|
||||||
|
|
||||||
|
if year < 1 || year > 9999 {
|
||||||
|
return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap
|
||||||
|
}
|
||||||
|
year100 := year / 100
|
||||||
|
year1 := year % 100
|
||||||
|
|
||||||
|
var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape
|
||||||
|
localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1]
|
||||||
|
localBuf[4] = '-'
|
||||||
|
localBuf[5], localBuf[6] = digits10[month], digits01[month]
|
||||||
|
localBuf[7] = '-'
|
||||||
|
localBuf[8], localBuf[9] = digits10[day], digits01[day]
|
||||||
|
|
||||||
|
if hour == 0 && min == 0 && sec == 0 && nsec == 0 {
|
||||||
|
return append(buf, localBuf[:10]...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
localBuf[10] = ' '
|
||||||
|
localBuf[11], localBuf[12] = digits10[hour], digits01[hour]
|
||||||
|
localBuf[13] = ':'
|
||||||
|
localBuf[14], localBuf[15] = digits10[min], digits01[min]
|
||||||
|
localBuf[16] = ':'
|
||||||
|
localBuf[17], localBuf[18] = digits10[sec], digits01[sec]
|
||||||
|
|
||||||
|
if nsec == 0 {
|
||||||
|
return append(buf, localBuf[:19]...), nil
|
||||||
|
}
|
||||||
|
nsec100000000 := nsec / 100000000
|
||||||
|
nsec1000000 := (nsec / 1000000) % 100
|
||||||
|
nsec10000 := (nsec / 10000) % 100
|
||||||
|
nsec100 := (nsec / 100) % 100
|
||||||
|
nsec1 := nsec % 100
|
||||||
|
localBuf[19] = '.'
|
||||||
|
|
||||||
|
// milli second
|
||||||
|
localBuf[20], localBuf[21], localBuf[22] =
|
||||||
|
digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000]
|
||||||
|
// micro second
|
||||||
|
localBuf[23], localBuf[24], localBuf[25] =
|
||||||
|
digits10[nsec10000], digits01[nsec10000], digits10[nsec100]
|
||||||
|
// nano second
|
||||||
|
localBuf[26], localBuf[27], localBuf[28] =
|
||||||
|
digits01[nsec100], digits10[nsec1], digits01[nsec1]
|
||||||
|
|
||||||
|
// trim trailing zeros
|
||||||
|
n := len(localBuf)
|
||||||
|
for n > 0 && localBuf[n-1] == '0' {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(buf, localBuf[:n]...), nil
|
||||||
|
}
|
||||||
|
|
||||||
// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
|
// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
|
||||||
// if the DATE or DATETIME has the zero value.
|
// if the DATE or DATETIME has the zero value.
|
||||||
// It must never be changed.
|
// It must never be changed.
|
||||||
|
1
vendor/github.com/pingcap/errors/.gitignore
generated
vendored
1
vendor/github.com/pingcap/errors/.gitignore
generated
vendored
@ -6,6 +6,7 @@
|
|||||||
# Folders
|
# Folders
|
||||||
_obj
|
_obj
|
||||||
_test
|
_test
|
||||||
|
.idea
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
# Architecture specific extensions/prefixes
|
||||||
*.[568vq]
|
*.[568vq]
|
||||||
|
99
vendor/github.com/pingcap/errors/compatible_shim.go
generated
vendored
Normal file
99
vendor/github.com/pingcap/errors/compatible_shim.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2020 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 errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// class2RFCCode is used for compatible with old version of TiDB. When
|
||||||
|
// marshal Error to json, old version of TiDB contain a 'class' field
|
||||||
|
// which is represented for error class. In order to parse and convert
|
||||||
|
// json to errors.Error, using this map to convert error class to RFC
|
||||||
|
// error code text. here is reference:
|
||||||
|
// https://github.com/pingcap/parser/blob/release-3.0/terror/terror.go#L58
|
||||||
|
var class2RFCCode = map[int]string{
|
||||||
|
1: "autoid",
|
||||||
|
2: "ddl",
|
||||||
|
3: "domain",
|
||||||
|
4: "evaluator",
|
||||||
|
5: "executor",
|
||||||
|
6: "expression",
|
||||||
|
7: "admin",
|
||||||
|
8: "kv",
|
||||||
|
9: "meta",
|
||||||
|
10: "planner",
|
||||||
|
11: "parser",
|
||||||
|
12: "perfschema",
|
||||||
|
13: "privilege",
|
||||||
|
14: "schema",
|
||||||
|
15: "server",
|
||||||
|
16: "struct",
|
||||||
|
17: "variable",
|
||||||
|
18: "xeval",
|
||||||
|
19: "table",
|
||||||
|
20: "types",
|
||||||
|
21: "global",
|
||||||
|
22: "mocktikv",
|
||||||
|
23: "json",
|
||||||
|
24: "tikv",
|
||||||
|
25: "session",
|
||||||
|
26: "plugin",
|
||||||
|
27: "util",
|
||||||
|
}
|
||||||
|
var rfcCode2class map[string]int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rfcCode2class = make(map[string]int)
|
||||||
|
for k, v := range class2RFCCode {
|
||||||
|
rfcCode2class[v] = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler interface.
|
||||||
|
// aware that this function cannot save a 'registered' status,
|
||||||
|
// since we cannot access the registry when unmarshaling,
|
||||||
|
// and the original global registry would be removed here.
|
||||||
|
// This function is reserved for compatibility.
|
||||||
|
func (e *Error) MarshalJSON() ([]byte, error) {
|
||||||
|
ec := strings.Split(string(e.codeText), ":")[0]
|
||||||
|
return json.Marshal(&jsonError{
|
||||||
|
Class: rfcCode2class[ec],
|
||||||
|
Code: int(e.code),
|
||||||
|
Msg: e.GetMsg(),
|
||||||
|
RFCCode: string(e.codeText),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
||||||
|
// aware that this function cannot create a 'registered' error,
|
||||||
|
// since we cannot access the registry in this context,
|
||||||
|
// and the original global registry is removed.
|
||||||
|
// This function is reserved for compatibility.
|
||||||
|
func (e *Error) UnmarshalJSON(data []byte) error {
|
||||||
|
tErr := &jsonError{}
|
||||||
|
if err := json.Unmarshal(data, &tErr); err != nil {
|
||||||
|
return Trace(err)
|
||||||
|
}
|
||||||
|
e.codeText = ErrCodeText(tErr.RFCCode)
|
||||||
|
if tErr.RFCCode == "" && tErr.Class > 0 {
|
||||||
|
e.codeText = ErrCodeText(class2RFCCode[tErr.Class] + ":" + strconv.Itoa(tErr.Code))
|
||||||
|
}
|
||||||
|
e.code = ErrCode(tErr.Code)
|
||||||
|
e.message = tErr.Msg
|
||||||
|
return nil
|
||||||
|
}
|
11
vendor/github.com/pingcap/errors/go.mod
generated
vendored
Normal file
11
vendor/github.com/pingcap/errors/go.mod
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module github.com/pingcap/errors
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8
|
||||||
|
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
go.uber.org/atomic v1.6.0
|
||||||
|
go.uber.org/zap v1.15.0
|
||||||
|
)
|
66
vendor/github.com/pingcap/errors/go.sum
generated
vendored
Normal file
66
vendor/github.com/pingcap/errors/go.sum
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
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/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
|
||||||
|
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
|
||||||
|
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
|
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad h1:SveG82rmu/GFxYanffxsSF503SiQV+2JLnWEiGiF+Tc=
|
||||||
|
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||||
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||||
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||||
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
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/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.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
45
vendor/github.com/pingcap/errors/juju_adaptor.go
generated
vendored
45
vendor/github.com/pingcap/errors/juju_adaptor.go
generated
vendored
@ -9,6 +9,9 @@ import (
|
|||||||
|
|
||||||
// Trace just calls AddStack.
|
// Trace just calls AddStack.
|
||||||
func Trace(err error) error {
|
func Trace(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return AddStack(err)
|
return AddStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +55,48 @@ func Annotatef(err error, format string, args ...interface{}) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var emptyStack stack
|
||||||
|
|
||||||
|
// NewNoStackError creates error without error stack
|
||||||
|
// later duplicate trace will no longer generate Stack too.
|
||||||
|
func NewNoStackError(msg string) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: msg,
|
||||||
|
stack: &emptyStack,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuspendStack suspends stack generate for error.
|
||||||
|
func SuspendStack(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cleared := clearStack(err)
|
||||||
|
if cleared {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
&emptyStack,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearStack(err error) (cleared bool) {
|
||||||
|
switch typedErr := err.(type) {
|
||||||
|
case *withMessage:
|
||||||
|
return clearStack(typedErr.Cause())
|
||||||
|
case *fundamental:
|
||||||
|
typedErr.stack = &emptyStack
|
||||||
|
return true
|
||||||
|
case *withStack:
|
||||||
|
typedErr.stack = &emptyStack
|
||||||
|
clearStack(typedErr.Cause())
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ErrorStack will format a stack trace if it is available, otherwise it will be Error()
|
// ErrorStack will format a stack trace if it is available, otherwise it will be Error()
|
||||||
// If the error is nil, the empty string is returned
|
// If the error is nil, the empty string is returned
|
||||||
// Note that this just calls fmt.Sprintf("%+v", err)
|
// Note that this just calls fmt.Sprintf("%+v", err)
|
||||||
|
313
vendor/github.com/pingcap/errors/normalize.go
generated
vendored
Normal file
313
vendor/github.com/pingcap/errors/normalize.go
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
// Copyright 2020 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 errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"go.uber.org/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RedactLogEnabled defines whether the arguments of Error need to be redacted.
|
||||||
|
var RedactLogEnabled atomic.Bool
|
||||||
|
|
||||||
|
// ErrCode represents a specific error type in a error class.
|
||||||
|
// Same error code can be used in different error classes.
|
||||||
|
type ErrCode int
|
||||||
|
|
||||||
|
// ErrCodeText is a textual error code that represents a specific error type in a error class.
|
||||||
|
type ErrCodeText string
|
||||||
|
|
||||||
|
type ErrorID string
|
||||||
|
type RFCErrorCode string
|
||||||
|
|
||||||
|
// Error is the 'prototype' of a type of errors.
|
||||||
|
// Use DefineError to make a *Error:
|
||||||
|
// var ErrUnavailable = errors.Normalize("Region %d is unavailable", errors.RFCCodeText("Unavailable"))
|
||||||
|
//
|
||||||
|
// "throw" it at runtime:
|
||||||
|
// func Somewhat() error {
|
||||||
|
// ...
|
||||||
|
// if err != nil {
|
||||||
|
// // generate a stackful error use the message template at defining,
|
||||||
|
// // also see FastGen(it's stackless), GenWithStack(it uses custom message template).
|
||||||
|
// return ErrUnavailable.GenWithStackByArgs(region.ID)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// testing whether an error belongs to a prototype:
|
||||||
|
// if ErrUnavailable.Equal(err) {
|
||||||
|
// // handle this error.
|
||||||
|
// }
|
||||||
|
type Error struct {
|
||||||
|
code ErrCode
|
||||||
|
// codeText is the textual describe of the error code
|
||||||
|
codeText ErrCodeText
|
||||||
|
// message is a template of the description of this error.
|
||||||
|
// printf-style formatting is enabled.
|
||||||
|
message string
|
||||||
|
// redactArgsPos defines the positions of arguments in message that need to be redacted.
|
||||||
|
// And it is controlled by the global var RedactLogEnabled.
|
||||||
|
// For example, an original error is `Duplicate entry 'PRIMARY' for key 'key'`,
|
||||||
|
// when RedactLogEnabled is ON and redactArgsPos is [0, 1], the error is `Duplicate entry '?' for key '?'`.
|
||||||
|
redactArgsPos []int
|
||||||
|
// Cause is used to warp some third party error.
|
||||||
|
cause error
|
||||||
|
args []interface{}
|
||||||
|
file string
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns the numeric code of this error.
|
||||||
|
// ID() will return textual error if there it is,
|
||||||
|
// when you just want to get the purely numeric error
|
||||||
|
// (e.g., for mysql protocol transmission.), this would be useful.
|
||||||
|
func (e *Error) Code() ErrCode {
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns ErrorCode, by the RFC:
|
||||||
|
//
|
||||||
|
// The error code is a 3-tuple of abbreviated component name, error class and error code,
|
||||||
|
// joined by a colon like {Component}:{ErrorClass}:{InnerErrorCode}.
|
||||||
|
func (e *Error) RFCCode() RFCErrorCode {
|
||||||
|
return RFCErrorCode(e.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the ID of this error.
|
||||||
|
func (e *Error) ID() ErrorID {
|
||||||
|
if e.codeText != "" {
|
||||||
|
return ErrorID(e.codeText)
|
||||||
|
}
|
||||||
|
return ErrorID(strconv.Itoa(int(e.code)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location returns the location where the error is created,
|
||||||
|
// implements juju/errors locationer interface.
|
||||||
|
func (e *Error) Location() (file string, line int) {
|
||||||
|
return e.file, e.line
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageTemplate returns the error message template of this error.
|
||||||
|
func (e *Error) MessageTemplate() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error interface.
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if e == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
describe := e.codeText
|
||||||
|
if len(describe) == 0 {
|
||||||
|
describe = ErrCodeText(strconv.Itoa(int(e.code)))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("[%s]%s", e.RFCCode(), e.GetMsg())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) GetMsg() string {
|
||||||
|
if len(e.args) > 0 {
|
||||||
|
return fmt.Sprintf(e.message, e.args...)
|
||||||
|
}
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) fillLineAndFile(skip int) {
|
||||||
|
// skip this
|
||||||
|
_, file, line, ok := runtime.Caller(skip + 1)
|
||||||
|
if !ok {
|
||||||
|
e.file = "<unknown>"
|
||||||
|
e.line = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.file = file
|
||||||
|
e.line = line
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenWithStack generates a new *Error with the same class and code, and a new formatted message.
|
||||||
|
func (e *Error) GenWithStack(format string, args ...interface{}) error {
|
||||||
|
// TODO: RedactErrorArg
|
||||||
|
err := *e
|
||||||
|
err.message = format
|
||||||
|
err.args = args
|
||||||
|
err.fillLineAndFile(1)
|
||||||
|
return AddStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenWithStackByArgs generates a new *Error with the same class and code, and new arguments.
|
||||||
|
func (e *Error) GenWithStackByArgs(args ...interface{}) error {
|
||||||
|
RedactErrorArg(args, e.redactArgsPos)
|
||||||
|
err := *e
|
||||||
|
err.args = args
|
||||||
|
err.fillLineAndFile(1)
|
||||||
|
return AddStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastGen generates a new *Error with the same class and code, and a new formatted message.
|
||||||
|
// This will not call runtime.Caller to get file and line.
|
||||||
|
func (e *Error) FastGen(format string, args ...interface{}) error {
|
||||||
|
// TODO: RedactErrorArg
|
||||||
|
err := *e
|
||||||
|
err.message = format
|
||||||
|
err.args = args
|
||||||
|
return SuspendStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastGen generates a new *Error with the same class and code, and a new arguments.
|
||||||
|
// This will not call runtime.Caller to get file and line.
|
||||||
|
func (e *Error) FastGenByArgs(args ...interface{}) error {
|
||||||
|
RedactErrorArg(args, e.redactArgsPos)
|
||||||
|
err := *e
|
||||||
|
err.args = args
|
||||||
|
return SuspendStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal checks if err is equal to e.
|
||||||
|
func (e *Error) Equal(err error) bool {
|
||||||
|
originErr := Cause(err)
|
||||||
|
if originErr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if error(e) == originErr {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
inErr, ok := originErr.(*Error)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
idEquals := e.ID() == inErr.ID()
|
||||||
|
return idEquals
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotEqual checks if err is not equal to e.
|
||||||
|
func (e *Error) NotEqual(err error) bool {
|
||||||
|
return !e.Equal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedactErrorArg redacts the args by position if RedactLogEnabled is enabled.
|
||||||
|
func RedactErrorArg(args []interface{}, position []int) {
|
||||||
|
if RedactLogEnabled.Load() {
|
||||||
|
for _, pos := range position {
|
||||||
|
if len(args) > pos {
|
||||||
|
args[pos] = "?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorEqual returns a boolean indicating whether err1 is equal to err2.
|
||||||
|
func ErrorEqual(err1, err2 error) bool {
|
||||||
|
e1 := Cause(err1)
|
||||||
|
e2 := Cause(err2)
|
||||||
|
|
||||||
|
if e1 == e2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if e1 == nil || e2 == nil {
|
||||||
|
return e1 == e2
|
||||||
|
}
|
||||||
|
|
||||||
|
te1, ok1 := e1.(*Error)
|
||||||
|
te2, ok2 := e2.(*Error)
|
||||||
|
if ok1 && ok2 {
|
||||||
|
return te1.Equal(te2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return e1.Error() == e2.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorNotEqual returns a boolean indicating whether err1 isn't equal to err2.
|
||||||
|
func ErrorNotEqual(err1, err2 error) bool {
|
||||||
|
return !ErrorEqual(err1, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonError struct {
|
||||||
|
// Deprecated field, please use `RFCCode` instead.
|
||||||
|
Class int `json:"class"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"message"`
|
||||||
|
RFCCode string `json:"rfccode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Wrap(err error) *Error {
|
||||||
|
if err != nil {
|
||||||
|
newErr := *e
|
||||||
|
newErr.cause = err
|
||||||
|
return &newErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Cause() error {
|
||||||
|
root := Unwrap(e.cause)
|
||||||
|
if root == nil {
|
||||||
|
return e.cause
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) FastGenWithCause(args ...interface{}) error {
|
||||||
|
err := *e
|
||||||
|
if e.cause != nil {
|
||||||
|
err.message = e.cause.Error()
|
||||||
|
}
|
||||||
|
err.args = args
|
||||||
|
return SuspendStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) GenWithStackByCause(args ...interface{}) error {
|
||||||
|
err := *e
|
||||||
|
if e.cause != nil {
|
||||||
|
err.message = e.cause.Error()
|
||||||
|
}
|
||||||
|
err.args = args
|
||||||
|
err.fillLineAndFile(1)
|
||||||
|
return AddStack(&err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NormalizeOption func(*Error)
|
||||||
|
|
||||||
|
func RedactArgs(pos []int) NormalizeOption {
|
||||||
|
return func(e *Error) {
|
||||||
|
e.redactArgsPos = pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFCCodeText returns a NormalizeOption to set RFC error code.
|
||||||
|
func RFCCodeText(codeText string) NormalizeOption {
|
||||||
|
return func(e *Error) {
|
||||||
|
e.codeText = ErrCodeText(codeText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MySQLErrorCode returns a NormalizeOption to set error code.
|
||||||
|
func MySQLErrorCode(code int) NormalizeOption {
|
||||||
|
return func(e *Error) {
|
||||||
|
e.code = ErrCode(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize creates a new Error object.
|
||||||
|
func Normalize(message string, opts ...NormalizeOption) *Error {
|
||||||
|
e := &Error{
|
||||||
|
message: message,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(e)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
33
vendor/github.com/siddontang/go-mysql/mysql/position.go
generated
vendored
33
vendor/github.com/siddontang/go-mysql/mysql/position.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// For binlog filename + position based replication
|
|
||||||
type Position struct {
|
|
||||||
Name string
|
|
||||||
Pos uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Position) Compare(o Position) int {
|
|
||||||
// First compare binlog name
|
|
||||||
if p.Name > o.Name {
|
|
||||||
return 1
|
|
||||||
} else if p.Name < o.Name {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
// Same binlog file, compare position
|
|
||||||
if p.Pos > o.Pos {
|
|
||||||
return 1
|
|
||||||
} else if p.Pos < o.Pos {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Position) String() string {
|
|
||||||
return fmt.Sprintf("(%s, %d)", p.Name, p.Pos)
|
|
||||||
}
|
|
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
coverage:
|
||||||
|
range: 80..100
|
||||||
|
round: down
|
||||||
|
precision: 2
|
||||||
|
|
||||||
|
status:
|
||||||
|
project: # measuring the overall project coverage
|
||||||
|
default: # context, you can create multiple ones with custom titles
|
||||||
|
enabled: yes # must be yes|true to enable this status
|
||||||
|
target: 100 # specify the target coverage for each commit status
|
||||||
|
# option: "auto" (must increase from parent commit or pull request base)
|
||||||
|
# option: "X%" a static target percentage to hit
|
||||||
|
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||||
|
if_ci_failed: error # if ci fails report status as success, error, or failure
|
||||||
|
|
||||||
|
# Also update COVER_IGNORE_PKGS in the Makefile.
|
||||||
|
ignore:
|
||||||
|
- /internal/gen-atomicint/
|
||||||
|
- /internal/gen-valuewrapper/
|
12
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
12
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/bin
|
||||||
|
.DS_Store
|
||||||
|
/vendor
|
||||||
|
cover.html
|
||||||
|
cover.out
|
||||||
|
lint.log
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Profiling output
|
||||||
|
*.prof
|
27
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
27
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go_import_path: go.uber.org/atomic
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- GO111MODULE=on
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- go: oldstable
|
||||||
|
- go: stable
|
||||||
|
env: LINT=1
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- go version
|
||||||
|
|
||||||
|
script:
|
||||||
|
- test -z "$LINT" || make lint
|
||||||
|
- make cover
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
76
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
76
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.7.0] - 2020-09-14
|
||||||
|
### Added
|
||||||
|
- Support JSON serialization and deserialization of primitive atomic types.
|
||||||
|
- Support Text marshalling and unmarshalling for string atomics.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Disallow incorrect comparison of atomic values in a non-atomic way.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Remove dependency on `golang.org/x/{lint, tools}`.
|
||||||
|
|
||||||
|
## [1.6.0] - 2020-02-24
|
||||||
|
### Changed
|
||||||
|
- Drop library dependency on `golang.org/x/{lint, tools}`.
|
||||||
|
|
||||||
|
## [1.5.1] - 2019-11-19
|
||||||
|
- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together
|
||||||
|
causing `CAS` to fail even though the old value matches.
|
||||||
|
|
||||||
|
## [1.5.0] - 2019-10-29
|
||||||
|
### Changed
|
||||||
|
- With Go modules, only the `go.uber.org/atomic` import path is supported now.
|
||||||
|
If you need to use the old import path, please add a `replace` directive to
|
||||||
|
your `go.mod`.
|
||||||
|
|
||||||
|
## [1.4.0] - 2019-05-01
|
||||||
|
### Added
|
||||||
|
- Add `atomic.Error` type for atomic operations on `error` values.
|
||||||
|
|
||||||
|
## [1.3.2] - 2018-05-02
|
||||||
|
### Added
|
||||||
|
- Add `atomic.Duration` type for atomic operations on `time.Duration` values.
|
||||||
|
|
||||||
|
## [1.3.1] - 2017-11-14
|
||||||
|
### Fixed
|
||||||
|
- Revert optimization for `atomic.String.Store("")` which caused data races.
|
||||||
|
|
||||||
|
## [1.3.0] - 2017-11-13
|
||||||
|
### Added
|
||||||
|
- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Optimize `atomic.String.Store("")` by avoiding an allocation.
|
||||||
|
|
||||||
|
## [1.2.0] - 2017-04-12
|
||||||
|
### Added
|
||||||
|
- Shadow `atomic.Value` from `sync/atomic`.
|
||||||
|
|
||||||
|
## [1.1.0] - 2017-03-10
|
||||||
|
### Added
|
||||||
|
- Add atomic `Float64` type.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Support new `go.uber.org/atomic` import path.
|
||||||
|
|
||||||
|
## [1.0.0] - 2016-07-18
|
||||||
|
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0
|
||||||
|
[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0
|
||||||
|
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||||
|
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||||
|
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||||
|
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||||
|
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||||
|
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||||
|
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||||
|
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||||
|
[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0
|
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
Normal file
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2016 Uber Technologies, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
78
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
78
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# Directory to place `go install`ed binaries into.
|
||||||
|
export GOBIN ?= $(shell pwd)/bin
|
||||||
|
|
||||||
|
GOLINT = $(GOBIN)/golint
|
||||||
|
GEN_ATOMICINT = $(GOBIN)/gen-atomicint
|
||||||
|
GEN_ATOMICWRAPPER = $(GOBIN)/gen-atomicwrapper
|
||||||
|
STATICCHECK = $(GOBIN)/staticcheck
|
||||||
|
|
||||||
|
GO_FILES ?= $(shell find . '(' -path .git -o -path vendor ')' -prune -o -name '*.go' -print)
|
||||||
|
|
||||||
|
# Also update ignore section in .codecov.yml.
|
||||||
|
COVER_IGNORE_PKGS = \
|
||||||
|
go.uber.org/atomic/internal/gen-atomicint \
|
||||||
|
go.uber.org/atomic/internal/gen-atomicwrapper
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
go build ./...
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test -race ./...
|
||||||
|
|
||||||
|
.PHONY: gofmt
|
||||||
|
gofmt:
|
||||||
|
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
|
||||||
|
gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
|
||||||
|
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" && cat $(FMT_LOG) && false)
|
||||||
|
|
||||||
|
$(GOLINT):
|
||||||
|
cd tools && go install golang.org/x/lint/golint
|
||||||
|
|
||||||
|
$(STATICCHECK):
|
||||||
|
cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||||
|
|
||||||
|
$(GEN_ATOMICWRAPPER): $(wildcard ./internal/gen-atomicwrapper/*)
|
||||||
|
go build -o $@ ./internal/gen-atomicwrapper
|
||||||
|
|
||||||
|
$(GEN_ATOMICINT): $(wildcard ./internal/gen-atomicint/*)
|
||||||
|
go build -o $@ ./internal/gen-atomicint
|
||||||
|
|
||||||
|
.PHONY: golint
|
||||||
|
golint: $(GOLINT)
|
||||||
|
$(GOLINT) ./...
|
||||||
|
|
||||||
|
.PHONY: staticcheck
|
||||||
|
staticcheck: $(STATICCHECK)
|
||||||
|
$(STATICCHECK) ./...
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: gofmt golint staticcheck generatenodirty
|
||||||
|
|
||||||
|
# comma separated list of packages to consider for code coverage.
|
||||||
|
COVER_PKG = $(shell \
|
||||||
|
go list -find ./... | \
|
||||||
|
grep -v $(foreach pkg,$(COVER_IGNORE_PKGS),-e "^$(pkg)$$") | \
|
||||||
|
paste -sd, -)
|
||||||
|
|
||||||
|
.PHONY: cover
|
||||||
|
cover:
|
||||||
|
go test -coverprofile=cover.out -coverpkg $(COVER_PKG) -v ./...
|
||||||
|
go tool cover -html=cover.out -o cover.html
|
||||||
|
|
||||||
|
.PHONY: generate
|
||||||
|
generate: $(GEN_ATOMICINT) $(GEN_ATOMICWRAPPER)
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
.PHONY: generatenodirty
|
||||||
|
generatenodirty:
|
||||||
|
@[ -z "$$(git status --porcelain)" ] || ( \
|
||||||
|
echo "Working tree is dirty. Commit your changes first."; \
|
||||||
|
exit 1 )
|
||||||
|
@make generate
|
||||||
|
@status=$$(git status --porcelain); \
|
||||||
|
[ -z "$$status" ] || ( \
|
||||||
|
echo "Working tree is dirty after `make generate`:"; \
|
||||||
|
echo "$$status"; \
|
||||||
|
echo "Please ensure that the generated code is up-to-date." )
|
63
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
63
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard]
|
||||||
|
|
||||||
|
Simple wrappers for primitive types to enforce atomic access.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ go get -u go.uber.org/atomic@v1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Legacy Import Path
|
||||||
|
|
||||||
|
As of v1.5.0, the import path `go.uber.org/atomic` is the only supported way
|
||||||
|
of using this package. If you are using Go modules, this package will fail to
|
||||||
|
compile with the legacy import path path `github.com/uber-go/atomic`.
|
||||||
|
|
||||||
|
We recommend migrating your code to the new import path but if you're unable
|
||||||
|
to do so, or if your dependencies are still using the old import path, you
|
||||||
|
will have to add a `replace` directive to your `go.mod` file downgrading the
|
||||||
|
legacy import path to an older version.
|
||||||
|
|
||||||
|
```
|
||||||
|
replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
You can do so automatically by running the following command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ go mod edit -replace github.com/uber-go/atomic=github.com/uber-go/atomic@v1.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The standard library's `sync/atomic` is powerful, but it's easy to forget which
|
||||||
|
variables must be accessed atomically. `go.uber.org/atomic` preserves all the
|
||||||
|
functionality of the standard library, but wraps the primitive types to
|
||||||
|
provide a safer, more convenient API.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var atom atomic.Uint32
|
||||||
|
atom.Store(42)
|
||||||
|
atom.Sub(2)
|
||||||
|
atom.CAS(40, 11)
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [documentation][doc] for a complete API specification.
|
||||||
|
|
||||||
|
## Development Status
|
||||||
|
|
||||||
|
Stable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Released under the [MIT License](LICENSE.txt).
|
||||||
|
|
||||||
|
[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg
|
||||||
|
[doc]: https://godoc.org/go.uber.org/atomic
|
||||||
|
[ci-img]: https://travis-ci.com/uber-go/atomic.svg?branch=master
|
||||||
|
[ci]: https://travis-ci.com/uber-go/atomic
|
||||||
|
[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg
|
||||||
|
[cov]: https://codecov.io/gh/uber-go/atomic
|
||||||
|
[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic
|
||||||
|
[reportcard]: https://goreportcard.com/report/go.uber.org/atomic
|
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
Normal file
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// @generated Code generated by gen-atomicwrapper.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bool is an atomic type-safe wrapper for bool values.
|
||||||
|
type Bool struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v Uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
var _zeroBool bool
|
||||||
|
|
||||||
|
// NewBool creates a new Bool.
|
||||||
|
func NewBool(v bool) *Bool {
|
||||||
|
x := &Bool{}
|
||||||
|
if v != _zeroBool {
|
||||||
|
x.Store(v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped bool.
|
||||||
|
func (x *Bool) Load() bool {
|
||||||
|
return truthy(x.v.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed bool.
|
||||||
|
func (x *Bool) Store(v bool) {
|
||||||
|
x.v.Store(boolToInt(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap for bool values.
|
||||||
|
func (x *Bool) CAS(o, n bool) bool {
|
||||||
|
return x.v.CAS(boolToInt(o), boolToInt(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically stores the given bool and returns the old
|
||||||
|
// value.
|
||||||
|
func (x *Bool) Swap(o bool) bool {
|
||||||
|
return truthy(x.v.Swap(boolToInt(o)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped bool into JSON.
|
||||||
|
func (x *Bool) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(x.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes a bool from JSON.
|
||||||
|
func (x *Bool) UnmarshalJSON(b []byte) error {
|
||||||
|
var v bool
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
x.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
Normal file
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicwrapper -name=Bool -type=bool -wrapped=Uint32 -pack=boolToInt -unpack=truthy -cas -swap -json -file=bool.go
|
||||||
|
|
||||||
|
func truthy(n uint32) bool {
|
||||||
|
return n == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToInt(b bool) uint32 {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle atomically negates the Boolean and returns the previous value.
|
||||||
|
func (b *Bool) Toggle() bool {
|
||||||
|
for {
|
||||||
|
old := b.Load()
|
||||||
|
if b.CAS(old, !old) {
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (b *Bool) String() string {
|
||||||
|
return strconv.FormatBool(b.Load())
|
||||||
|
}
|
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
Normal file
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
// Package atomic provides simple wrappers around numerics to enforce atomic
|
||||||
|
// access.
|
||||||
|
package atomic
|
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
Normal file
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// @generated Code generated by gen-atomicwrapper.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Duration is an atomic type-safe wrapper for time.Duration values.
|
||||||
|
type Duration struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var _zeroDuration time.Duration
|
||||||
|
|
||||||
|
// NewDuration creates a new Duration.
|
||||||
|
func NewDuration(v time.Duration) *Duration {
|
||||||
|
x := &Duration{}
|
||||||
|
if v != _zeroDuration {
|
||||||
|
x.Store(v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped time.Duration.
|
||||||
|
func (x *Duration) Load() time.Duration {
|
||||||
|
return time.Duration(x.v.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed time.Duration.
|
||||||
|
func (x *Duration) Store(v time.Duration) {
|
||||||
|
x.v.Store(int64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap for time.Duration values.
|
||||||
|
func (x *Duration) CAS(o, n time.Duration) bool {
|
||||||
|
return x.v.CAS(int64(o), int64(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically stores the given time.Duration and returns the old
|
||||||
|
// value.
|
||||||
|
func (x *Duration) Swap(o time.Duration) time.Duration {
|
||||||
|
return time.Duration(x.v.Swap(int64(o)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped time.Duration into JSON.
|
||||||
|
func (x *Duration) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(x.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes a time.Duration from JSON.
|
||||||
|
func (x *Duration) UnmarshalJSON(b []byte) error {
|
||||||
|
var v time.Duration
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
x.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
Normal file
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicwrapper -name=Duration -type=time.Duration -wrapped=Int64 -pack=int64 -unpack=time.Duration -cas -swap -json -imports time -file=duration.go
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||||
|
func (d *Duration) Add(n time.Duration) time.Duration {
|
||||||
|
return time.Duration(d.v.Add(int64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||||
|
func (d *Duration) Sub(n time.Duration) time.Duration {
|
||||||
|
return time.Duration(d.v.Sub(int64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (d *Duration) String() string {
|
||||||
|
return d.Load().String()
|
||||||
|
}
|
51
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
51
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// @generated Code generated by gen-atomicwrapper.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
// Error is an atomic type-safe wrapper for error values.
|
||||||
|
type Error struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var _zeroError error
|
||||||
|
|
||||||
|
// NewError creates a new Error.
|
||||||
|
func NewError(v error) *Error {
|
||||||
|
x := &Error{}
|
||||||
|
if v != _zeroError {
|
||||||
|
x.Store(v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped error.
|
||||||
|
func (x *Error) Load() error {
|
||||||
|
return unpackError(x.v.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed error.
|
||||||
|
func (x *Error) Store(v error) {
|
||||||
|
x.v.Store(packError(v))
|
||||||
|
}
|
39
vendor/go.uber.org/atomic/error_ext.go
generated
vendored
Normal file
39
vendor/go.uber.org/atomic/error_ext.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
// atomic.Value panics on nil inputs, or if the underlying type changes.
|
||||||
|
// Stabilize by always storing a custom struct that we control.
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicwrapper -name=Error -type=error -wrapped=Value -pack=packError -unpack=unpackError -file=error.go
|
||||||
|
|
||||||
|
type packedError struct{ Value error }
|
||||||
|
|
||||||
|
func packError(v error) interface{} {
|
||||||
|
return packedError{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpackError(v interface{}) error {
|
||||||
|
if err, ok := v.(packedError); ok {
|
||||||
|
return err.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
76
vendor/go.uber.org/atomic/float64.go
generated
vendored
Normal file
76
vendor/go.uber.org/atomic/float64.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// @generated Code generated by gen-atomicwrapper.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Float64 is an atomic type-safe wrapper for float64 values.
|
||||||
|
type Float64 struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v Uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var _zeroFloat64 float64
|
||||||
|
|
||||||
|
// NewFloat64 creates a new Float64.
|
||||||
|
func NewFloat64(v float64) *Float64 {
|
||||||
|
x := &Float64{}
|
||||||
|
if v != _zeroFloat64 {
|
||||||
|
x.Store(v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped float64.
|
||||||
|
func (x *Float64) Load() float64 {
|
||||||
|
return math.Float64frombits(x.v.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed float64.
|
||||||
|
func (x *Float64) Store(v float64) {
|
||||||
|
x.v.Store(math.Float64bits(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap for float64 values.
|
||||||
|
func (x *Float64) CAS(o, n float64) bool {
|
||||||
|
return x.v.CAS(math.Float64bits(o), math.Float64bits(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped float64 into JSON.
|
||||||
|
func (x *Float64) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(x.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes a float64 from JSON.
|
||||||
|
func (x *Float64) UnmarshalJSON(b []byte) error {
|
||||||
|
var v float64
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
x.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
47
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
Normal file
47
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -cas -json -imports math -file=float64.go
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped float64 and returns the new value.
|
||||||
|
func (f *Float64) Add(s float64) float64 {
|
||||||
|
for {
|
||||||
|
old := f.Load()
|
||||||
|
new := old + s
|
||||||
|
if f.CAS(old, new) {
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped float64 and returns the new value.
|
||||||
|
func (f *Float64) Sub(s float64) float64 {
|
||||||
|
return f.Add(-s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (f *Float64) String() string {
|
||||||
|
// 'g' is the behavior for floats with %v.
|
||||||
|
return strconv.FormatFloat(f.Load(), 'g', -1, 64)
|
||||||
|
}
|
26
vendor/go.uber.org/atomic/gen.go
generated
vendored
Normal file
26
vendor/go.uber.org/atomic/gen.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicint -name=Int32 -wrapped=int32 -file=int32.go
|
||||||
|
//go:generate bin/gen-atomicint -name=Int64 -wrapped=int64 -file=int64.go
|
||||||
|
//go:generate bin/gen-atomicint -name=Uint32 -wrapped=uint32 -unsigned -file=uint32.go
|
||||||
|
//go:generate bin/gen-atomicint -name=Uint64 -wrapped=uint64 -unsigned -file=uint64.go
|
8
vendor/go.uber.org/atomic/go.mod
generated
vendored
Normal file
8
vendor/go.uber.org/atomic/go.mod
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module go.uber.org/atomic
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/stretchr/testify v1.3.0
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
9
vendor/go.uber.org/atomic/go.sum
generated
vendored
Normal file
9
vendor/go.uber.org/atomic/go.sum
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// @generated Code generated by gen-atomicint.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Int32 is an atomic wrapper around int32.
|
||||||
|
type Int32 struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInt32 creates a new Int32.
|
||||||
|
func NewInt32(i int32) *Int32 {
|
||||||
|
return &Int32{v: i}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped value.
|
||||||
|
func (i *Int32) Load() int32 {
|
||||||
|
return atomic.LoadInt32(&i.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped int32 and returns the new value.
|
||||||
|
func (i *Int32) Add(n int32) int32 {
|
||||||
|
return atomic.AddInt32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped int32 and returns the new value.
|
||||||
|
func (i *Int32) Sub(n int32) int32 {
|
||||||
|
return atomic.AddInt32(&i.v, -n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc atomically increments the wrapped int32 and returns the new value.
|
||||||
|
func (i *Int32) Inc() int32 {
|
||||||
|
return i.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||||
|
func (i *Int32) Dec() int32 {
|
||||||
|
return i.Sub(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (i *Int32) CAS(old, new int32) bool {
|
||||||
|
return atomic.CompareAndSwapInt32(&i.v, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed value.
|
||||||
|
func (i *Int32) Store(n int32) {
|
||||||
|
atomic.StoreInt32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||||
|
func (i *Int32) Swap(n int32) int32 {
|
||||||
|
return atomic.SwapInt32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped int32 into JSON.
|
||||||
|
func (i *Int32) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(i.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes JSON into the wrapped int32.
|
||||||
|
func (i *Int32) UnmarshalJSON(b []byte) error {
|
||||||
|
var v int32
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (i *Int32) String() string {
|
||||||
|
v := i.Load()
|
||||||
|
return strconv.FormatInt(int64(v), 10)
|
||||||
|
}
|
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// @generated Code generated by gen-atomicint.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Int64 is an atomic wrapper around int64.
|
||||||
|
type Int64 struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInt64 creates a new Int64.
|
||||||
|
func NewInt64(i int64) *Int64 {
|
||||||
|
return &Int64{v: i}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped value.
|
||||||
|
func (i *Int64) Load() int64 {
|
||||||
|
return atomic.LoadInt64(&i.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped int64 and returns the new value.
|
||||||
|
func (i *Int64) Add(n int64) int64 {
|
||||||
|
return atomic.AddInt64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped int64 and returns the new value.
|
||||||
|
func (i *Int64) Sub(n int64) int64 {
|
||||||
|
return atomic.AddInt64(&i.v, -n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc atomically increments the wrapped int64 and returns the new value.
|
||||||
|
func (i *Int64) Inc() int64 {
|
||||||
|
return i.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dec atomically decrements the wrapped int64 and returns the new value.
|
||||||
|
func (i *Int64) Dec() int64 {
|
||||||
|
return i.Sub(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (i *Int64) CAS(old, new int64) bool {
|
||||||
|
return atomic.CompareAndSwapInt64(&i.v, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed value.
|
||||||
|
func (i *Int64) Store(n int64) {
|
||||||
|
atomic.StoreInt64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||||
|
func (i *Int64) Swap(n int64) int64 {
|
||||||
|
return atomic.SwapInt64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped int64 into JSON.
|
||||||
|
func (i *Int64) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(i.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes JSON into the wrapped int64.
|
||||||
|
func (i *Int64) UnmarshalJSON(b []byte) error {
|
||||||
|
var v int64
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (i *Int64) String() string {
|
||||||
|
v := i.Load()
|
||||||
|
return strconv.FormatInt(int64(v), 10)
|
||||||
|
}
|
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
Normal file
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
// nocmp is an uncomparable struct. Embed this inside another struct to make
|
||||||
|
// it uncomparable.
|
||||||
|
//
|
||||||
|
// type Foo struct {
|
||||||
|
// nocmp
|
||||||
|
// // ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This DOES NOT:
|
||||||
|
//
|
||||||
|
// - Disallow shallow copies of structs
|
||||||
|
// - Disallow comparison of pointers to uncomparable structs
|
||||||
|
type nocmp [0]func()
|
54
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
54
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// @generated Code generated by gen-atomicwrapper.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
// String is an atomic type-safe wrapper for string values.
|
||||||
|
type String struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var _zeroString string
|
||||||
|
|
||||||
|
// NewString creates a new String.
|
||||||
|
func NewString(v string) *String {
|
||||||
|
x := &String{}
|
||||||
|
if v != _zeroString {
|
||||||
|
x.Store(v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped string.
|
||||||
|
func (x *String) Load() string {
|
||||||
|
if v := x.v.Load(); v != nil {
|
||||||
|
return v.(string)
|
||||||
|
}
|
||||||
|
return _zeroString
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed string.
|
||||||
|
func (x *String) Store(v string) {
|
||||||
|
x.v.Store(v)
|
||||||
|
}
|
43
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
Normal file
43
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
//go:generate bin/gen-atomicwrapper -name=String -type=string -wrapped=Value -file=string.go
|
||||||
|
|
||||||
|
// String returns the wrapped value.
|
||||||
|
func (s *String) String() string {
|
||||||
|
return s.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the wrapped string into a textual form.
|
||||||
|
//
|
||||||
|
// This makes it encodable as JSON, YAML, XML, and more.
|
||||||
|
func (s *String) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(s.Load()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText decodes text and replaces the wrapped string with it.
|
||||||
|
//
|
||||||
|
// This makes it decodable from JSON, YAML, XML, and more.
|
||||||
|
func (s *String) UnmarshalText(b []byte) error {
|
||||||
|
s.Store(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// @generated Code generated by gen-atomicint.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Uint32 is an atomic wrapper around uint32.
|
||||||
|
type Uint32 struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUint32 creates a new Uint32.
|
||||||
|
func NewUint32(i uint32) *Uint32 {
|
||||||
|
return &Uint32{v: i}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped value.
|
||||||
|
func (i *Uint32) Load() uint32 {
|
||||||
|
return atomic.LoadUint32(&i.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped uint32 and returns the new value.
|
||||||
|
func (i *Uint32) Add(n uint32) uint32 {
|
||||||
|
return atomic.AddUint32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
|
||||||
|
func (i *Uint32) Sub(n uint32) uint32 {
|
||||||
|
return atomic.AddUint32(&i.v, ^(n - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc atomically increments the wrapped uint32 and returns the new value.
|
||||||
|
func (i *Uint32) Inc() uint32 {
|
||||||
|
return i.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dec atomically decrements the wrapped uint32 and returns the new value.
|
||||||
|
func (i *Uint32) Dec() uint32 {
|
||||||
|
return i.Sub(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (i *Uint32) CAS(old, new uint32) bool {
|
||||||
|
return atomic.CompareAndSwapUint32(&i.v, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed value.
|
||||||
|
func (i *Uint32) Store(n uint32) {
|
||||||
|
atomic.StoreUint32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||||
|
func (i *Uint32) Swap(n uint32) uint32 {
|
||||||
|
return atomic.SwapUint32(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped uint32 into JSON.
|
||||||
|
func (i *Uint32) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(i.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes JSON into the wrapped uint32.
|
||||||
|
func (i *Uint32) UnmarshalJSON(b []byte) error {
|
||||||
|
var v uint32
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (i *Uint32) String() string {
|
||||||
|
v := i.Load()
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
}
|
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// @generated Code generated by gen-atomicint.
|
||||||
|
|
||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Uint64 is an atomic wrapper around uint64.
|
||||||
|
type Uint64 struct {
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
|
||||||
|
v uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUint64 creates a new Uint64.
|
||||||
|
func NewUint64(i uint64) *Uint64 {
|
||||||
|
return &Uint64{v: i}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped value.
|
||||||
|
func (i *Uint64) Load() uint64 {
|
||||||
|
return atomic.LoadUint64(&i.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped uint64 and returns the new value.
|
||||||
|
func (i *Uint64) Add(n uint64) uint64 {
|
||||||
|
return atomic.AddUint64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
|
||||||
|
func (i *Uint64) Sub(n uint64) uint64 {
|
||||||
|
return atomic.AddUint64(&i.v, ^(n - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc atomically increments the wrapped uint64 and returns the new value.
|
||||||
|
func (i *Uint64) Inc() uint64 {
|
||||||
|
return i.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dec atomically decrements the wrapped uint64 and returns the new value.
|
||||||
|
func (i *Uint64) Dec() uint64 {
|
||||||
|
return i.Sub(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (i *Uint64) CAS(old, new uint64) bool {
|
||||||
|
return atomic.CompareAndSwapUint64(&i.v, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed value.
|
||||||
|
func (i *Uint64) Store(n uint64) {
|
||||||
|
atomic.StoreUint64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||||
|
func (i *Uint64) Swap(n uint64) uint64 {
|
||||||
|
return atomic.SwapUint64(&i.v, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the wrapped uint64 into JSON.
|
||||||
|
func (i *Uint64) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(i.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes JSON into the wrapped uint64.
|
||||||
|
func (i *Uint64) UnmarshalJSON(b []byte) error {
|
||||||
|
var v uint64
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Store(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the wrapped value as a string.
|
||||||
|
func (i *Uint64) String() string {
|
||||||
|
v := i.Load()
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
}
|
31
vendor/go.uber.org/atomic/value.go
generated
vendored
Normal file
31
vendor/go.uber.org/atomic/value.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package atomic
|
||||||
|
|
||||||
|
import "sync/atomic"
|
||||||
|
|
||||||
|
// Value shadows the type of the same name from sync/atomic
|
||||||
|
// https://godoc.org/sync/atomic#Value
|
||||||
|
type Value struct {
|
||||||
|
atomic.Value
|
||||||
|
|
||||||
|
_ nocmp // disallow non-atomic comparison
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user