mirror of https://github.com/tikv/client-go.git
add client proxy and proxy server example (#11)
* add proxy Signed-off-by: disksing <i@disksing.com>
This commit is contained in:
parent
112f5cb76e
commit
c1e45e6cd9
|
|
@ -1 +1,2 @@
|
|||
vendor
|
||||
vendor
|
||||
go.sum
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2019 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 main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tikv/client-go/proxy/httpproxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.ListenAndServe(":8080", httpproxy.NewHTTPProxyHandler())
|
||||
}
|
||||
3
go.mod
3
go.mod
|
|
@ -16,7 +16,8 @@ require (
|
|||
github.com/golang/protobuf v1.2.0
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c
|
||||
github.com/gorilla/mux v1.7.0 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/mux v1.7.0
|
||||
github.com/gorilla/websocket v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
|
|
|
|||
179
go.sum
179
go.sum
|
|
@ -1,179 +0,0 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.12+incompatible h1:pAWNwdf7QiT1zfaWyqCtNZQWCLByQyA3JrSQyuYAqnQ=
|
||||
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76 h1:FE783w8WFh+Rvg+7bZ5g8p7gP4SeVS4AoNwkvazlsBg=
|
||||
github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||
github.com/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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gogo/protobuf v0.0.0-20180717141946-636bf0302bc9 h1:EGUd+AQfZoi1OwZAoqekLbl4kq6tafFtKQSiN8nL21Y=
|
||||
github.com/gogo/protobuf v0.0.0-20180717141946-636bf0302bc9/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.1 h1:VNUuLKyFcJ5IektwBKcZU4J5GJKEt+Odb8dl1d61BGQ=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.1/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 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/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/montanaflynn/stats v0.5.0 h1:2EkzeTSqBB4V4bJwWrt5gIIrZmpJBcoIRGS2kWLgzmk=
|
||||
github.com/montanaflynn/stats v0.5.0/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
|
||||
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
|
||||
github.com/pingcap/gofail v0.0.0-20181217135706-6a951c1e42c3 h1:04yuCf5NMvLU8rB2m4Qs3rynH7EYpMno3lHkewIOdMo=
|
||||
github.com/pingcap/gofail v0.0.0-20181217135706-6a951c1e42c3/go.mod h1:DazNTg0PTldtpsQiT9I5tVJwV1onHMKBBgXzmJUlMns=
|
||||
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8=
|
||||
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
|
||||
github.com/pingcap/kvproto v0.0.0-20190305055742-ab7debc182d9 h1:EsTt42btov+tFchxOFKnxBNmXOWyPKiddOwvr/WO90g=
|
||||
github.com/pingcap/kvproto v0.0.0-20190305055742-ab7debc182d9/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY=
|
||||
github.com/pingcap/pd v2.1.5+incompatible h1:vOLV2tSQdRjjmxaTXtJULoC94dYQOd+6fzn2yChODHc=
|
||||
github.com/pingcap/pd v2.1.5+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.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/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446 h1:/NRJ5vAYoqz+7sG51ubIDHXeWO8DlTSrToPu6q11ziA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs=
|
||||
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 h1:BasDe+IErOQKrMVXab7UayvSlIpiyGwRvuX3EKYY7UA=
|
||||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
|
||||
github.com/unrolled/render v1.0.0 h1:XYtvhA3UkpB7PqkvhUFYmpKD55OudoIeygcfus4vcd4=
|
||||
github.com/unrolled/render v1.0.0/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f h1:FU37niK8AQ59mHcskRyQL7H0ErSeNh650vdcj8HqdSI=
|
||||
google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v0.0.0-20180607172857-7a6a684ca69e/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
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/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2019 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 httpproxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tikv/client-go/proxy"
|
||||
)
|
||||
|
||||
// NewHTTPProxyHandler creates an http.Handler that serves as a TiKV client proxy.
|
||||
func NewHTTPProxyHandler() http.Handler {
|
||||
router := mux.NewRouter()
|
||||
rawkv := rawkvHandler{p: proxy.NewRaw()}
|
||||
|
||||
router.HandleFunc("/rawkv/client/new", rawkv.handlerFunc(rawkv.New))
|
||||
router.HandleFunc("/rawkv/client/{id}/close", rawkv.handlerFunc(rawkv.Close))
|
||||
router.HandleFunc("/rawkv/client/{id}/get", rawkv.handlerFunc(rawkv.Get))
|
||||
router.HandleFunc("/rawkv/client/{id}/batch-get", rawkv.handlerFunc(rawkv.BatchGet))
|
||||
router.HandleFunc("/rawkv/client/{id}/put", rawkv.handlerFunc(rawkv.Put))
|
||||
router.HandleFunc("/rawkv/client/{id}/batch-put", rawkv.handlerFunc(rawkv.BatchPut))
|
||||
router.HandleFunc("/rawkv/client/{id}/delete", rawkv.handlerFunc(rawkv.Delete))
|
||||
router.HandleFunc("/rawkv/client/{id}/batch-delete", rawkv.handlerFunc(rawkv.BatchDelete))
|
||||
router.HandleFunc("/rawkv/client/{id}/delete-range", rawkv.handlerFunc(rawkv.DeleteRange))
|
||||
router.HandleFunc("/rawkv/client/{id}/scan", rawkv.handlerFunc(rawkv.Scan))
|
||||
|
||||
txnkv := txnkvHandler{p: proxy.NewTxn()}
|
||||
router.HandleFunc("/txnkv/client/new", txnkv.handlerFunc(txnkv.New))
|
||||
router.HandleFunc("/txnkv/client/{id}/close", txnkv.handlerFunc(txnkv.Close))
|
||||
router.HandleFunc("/txnkv/client/{id}/begin", txnkv.handlerFunc(txnkv.Begin))
|
||||
router.HandleFunc("/txnkv/client/{id}/begin-with-ts", txnkv.handlerFunc(txnkv.BeginWithTS))
|
||||
router.HandleFunc("/txnkv/client/{id}/get-ts", txnkv.handlerFunc(txnkv.GetTS))
|
||||
router.HandleFunc("/txnkv/txn/{id}/get", txnkv.handlerFunc(txnkv.TxnGet))
|
||||
router.HandleFunc("/txnkv/txn/{id}/batch-get", txnkv.handlerFunc(txnkv.TxnBatchGet))
|
||||
router.HandleFunc("/txnkv/txn/{id}/set", txnkv.handlerFunc(txnkv.TxnSet))
|
||||
router.HandleFunc("/txnkv/txn/{id}/iter", txnkv.handlerFunc(txnkv.TxnIter))
|
||||
router.HandleFunc("/txnkv/txn/{id}/iter-reverse", txnkv.handlerFunc(txnkv.TxnIterReverse))
|
||||
router.HandleFunc("/txnkv/txn/{id}/readonly", txnkv.handlerFunc(txnkv.TxnIsReadOnly))
|
||||
router.HandleFunc("/txnkv/txn/{id}/delete", txnkv.handlerFunc(txnkv.TxnDelete))
|
||||
router.HandleFunc("/txnkv/txn/{id}/commit", txnkv.handlerFunc(txnkv.TxnCommit))
|
||||
router.HandleFunc("/txnkv/txn/{id}/rollback", txnkv.handlerFunc(txnkv.TxnRollback))
|
||||
router.HandleFunc("/txnkv/txn/{id}/lock-keys", txnkv.handlerFunc(txnkv.TxnLockKeys))
|
||||
router.HandleFunc("/txnkv/txn/{id}/valid", txnkv.handlerFunc(txnkv.TxnValid))
|
||||
router.HandleFunc("/txnkv/txn/{id}/len", txnkv.handlerFunc(txnkv.TxnLen))
|
||||
router.HandleFunc("/txnkv/txn/{id}/size", txnkv.handlerFunc(txnkv.TxnSize))
|
||||
router.HandleFunc("/txnkv/iter/{id}/valid", txnkv.handlerFunc(txnkv.IterValid))
|
||||
router.HandleFunc("/txnkv/iter/{id}/key", txnkv.handlerFunc(txnkv.IterKey))
|
||||
router.HandleFunc("/txnkv/iter/{id}/value", txnkv.handlerFunc(txnkv.IterValue))
|
||||
router.HandleFunc("/txnkv/iter/{id}/next", txnkv.handlerFunc(txnkv.IterNext))
|
||||
router.HandleFunc("/txnkv/iter/{id}/close", txnkv.handlerFunc(txnkv.IterClose))
|
||||
|
||||
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
w.Write([]byte("not implemented"))
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2019 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 httpproxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tikv/client-go/config"
|
||||
"github.com/tikv/client-go/proxy"
|
||||
)
|
||||
|
||||
type rawkvHandler struct {
|
||||
p proxy.RawKVProxy
|
||||
}
|
||||
|
||||
// RawRequest is the structure of a rawkv request that the http proxy accepts.
|
||||
type RawRequest struct {
|
||||
PDAddrs []string `json:"pd_addrs,omitempty"` // for new
|
||||
Key []byte `json:"key,omitempty"` // for get, put, delete
|
||||
Keys [][]byte `json:"keys,omitempty"` // for batchGet, batchPut, batchDelete
|
||||
Value []byte `json:"value,omitempty"` // for put
|
||||
Values [][]byte `json:"values,omitmepty"` // for batchPut
|
||||
StartKey []byte `json:"start_key,omitempty"` // for scan, deleteRange
|
||||
EndKey []byte `json:"end_key,omitempty"` // for scan, deleteRange
|
||||
Limit int `json:"limit,omitempty"` // for scan
|
||||
}
|
||||
|
||||
// RawResponse is the structure of a rawkv response that the http proxy sends.
|
||||
type RawResponse struct {
|
||||
ID string `json:"id,omitempty"` // for new
|
||||
Value []byte `json:"value,omitempty"` // for get
|
||||
Keys [][]byte `json:"keys,omitempty"` // for scan
|
||||
Values [][]byte `json:"values,omitempty"` // for batchGet
|
||||
}
|
||||
|
||||
func (h rawkvHandler) New(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
id, err := h.p.New(r.PDAddrs, config.Security{})
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{ID: string(id)}, http.StatusCreated, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) Close(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
if err := h.p.Close(proxy.UUID(vars["id"])); err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) Get(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
val, err := h.p.Get(proxy.UUID(vars["id"]), r.Key)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{Value: val}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) BatchGet(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
vals, err := h.p.BatchGet(proxy.UUID(vars["id"]), r.Keys)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{Values: vals}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) Put(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
err := h.p.Put(proxy.UUID(vars["id"]), r.Key, r.Value)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) BatchPut(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
err := h.p.BatchPut(proxy.UUID(vars["id"]), r.Keys, r.Values)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) Delete(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
err := h.p.Delete(proxy.UUID(vars["id"]), r.Key)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) BatchDelete(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
err := h.p.BatchDelete(proxy.UUID(vars["id"]), r.Keys)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) DeleteRange(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
err := h.p.DeleteRange(proxy.UUID(vars["id"]), r.StartKey, r.EndKey)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) Scan(vars map[string]string, r *RawRequest) (*RawResponse, int, error) {
|
||||
keys, values, err := h.p.Scan(proxy.UUID(vars["id"]), r.StartKey, r.EndKey, r.Limit)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &RawResponse{Keys: keys, Values: values}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h rawkvHandler) handlerFunc(f func(map[string]string, *RawRequest) (*RawResponse, int, error)) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
sendError(w, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var req RawRequest
|
||||
if err = json.Unmarshal(data, &req); err != nil {
|
||||
sendError(w, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
res, status, err := f(mux.Vars(r), &req)
|
||||
if err != nil {
|
||||
sendError(w, err, status)
|
||||
return
|
||||
}
|
||||
data, err = json.Marshal(res)
|
||||
if err != nil {
|
||||
sendError(w, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
w.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
func sendError(w http.ResponseWriter, err error, status int) {
|
||||
w.WriteHeader(status)
|
||||
w.Write([]byte(err.Error()))
|
||||
}
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
// Copyright 2019 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 httpproxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tikv/client-go/config"
|
||||
"github.com/tikv/client-go/proxy"
|
||||
)
|
||||
|
||||
type txnkvHandler struct {
|
||||
p proxy.TxnKVProxy
|
||||
}
|
||||
|
||||
// TxnRequest is the structure of a txnkv request that the http proxy accepts.
|
||||
type TxnRequest struct {
|
||||
PDAddrs []string `json:"pd_addrs,omitempty"` // for new
|
||||
TS uint64 `json:"ts,omitempty"` // for beginWithTS
|
||||
Key []byte `json:"key,omitempty"` // for get, set, delete, iter, iterReverse
|
||||
Value []byte `json:"value,omitempty"` // for set
|
||||
Keys [][]byte `json:"keys,omitempty"` // for batchGet, lockKeys
|
||||
UpperBound []byte `json:"upper_bound,omitempty"` // for iter
|
||||
}
|
||||
|
||||
// TxnResponse is the structure of a txnkv response that the http proxy sends.
|
||||
type TxnResponse struct {
|
||||
ID string `json:"id,omitempty"` // for new, begin, beginWithTS, iter, iterReverse
|
||||
TS uint64 `json:"ts,omitempty"` // for getTS
|
||||
Key []byte `json:"key,omitempty"` // for iterKey
|
||||
Value []byte `json:"value,omitempty"` // for get, iterValue
|
||||
Keys [][]byte `json:"keys,omitempty"` // for batchGet
|
||||
Values [][]byte `json:"values,omitempty"` // for batchGet
|
||||
IsValid bool `json:"is_valid,omitempty"` // for valid, iterValid
|
||||
IsReadOnly bool `json:"is_readonly,omitempty"` // for isReadOnly
|
||||
Size int `json:"size,omitempty"` // for size
|
||||
Length int `json:"length,omitempty"` // for length
|
||||
}
|
||||
|
||||
func (h txnkvHandler) New(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
id, err := h.p.New(r.PDAddrs, config.Security{})
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{ID: string(id)}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) Close(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.Close(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) Begin(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
txnID, err := h.p.Begin(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{ID: string(txnID)}, http.StatusCreated, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) BeginWithTS(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
txnID, err := h.p.BeginWithTS(proxy.UUID(vars["id"]), r.TS)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{ID: string(txnID)}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) GetTS(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
ts, err := h.p.GetTS(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{TS: ts}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnGet(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
val, err := h.p.TxnGet(proxy.UUID(vars["id"]), r.Key)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{Value: val}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnBatchGet(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
m, err := h.p.TxnBatchGet(proxy.UUID(vars["id"]), r.Keys)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
keys, values := make([][]byte, 0, len(m)), make([][]byte, 0, len(m))
|
||||
for k, v := range m {
|
||||
keys = append(keys, []byte(k))
|
||||
values = append(values, v)
|
||||
}
|
||||
return &TxnResponse{Keys: keys, Values: values}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnSet(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.TxnSet(proxy.UUID(vars["id"]), r.Key, r.Value)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnIter(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
iterID, err := h.p.TxnIter(proxy.UUID(vars["id"]), r.Key, r.UpperBound)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{ID: string(iterID)}, http.StatusCreated, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnIterReverse(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
iterID, err := h.p.TxnIterReverse(proxy.UUID(vars["id"]), r.Key)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{ID: string(iterID)}, http.StatusCreated, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnIsReadOnly(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
readonly, err := h.p.TxnIsReadOnly(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{IsReadOnly: readonly}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnDelete(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.TxnDelete(proxy.UUID(vars["id"]), r.Key)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnCommit(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.TxnCommit(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnRollback(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.TxnRollback(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnLockKeys(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.TxnLockKeys(proxy.UUID(vars["id"]), r.Keys)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnValid(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
valid, err := h.p.TxnValid(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{IsValid: valid}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnLen(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
length, err := h.p.TxnLen(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{Length: length}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) TxnSize(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
size, err := h.p.TxnSize(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{Size: size}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) IterValid(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
valid, err := h.p.IterValid(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{IsValid: valid}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) IterKey(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
key, err := h.p.IterKey(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{Key: key}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) IterValue(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
val, err := h.p.IterValue(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{Value: val}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) IterNext(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.IterNext(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) IterClose(vars map[string]string, r *TxnRequest) (*TxnResponse, int, error) {
|
||||
err := h.p.IterClose(proxy.UUID(vars["id"]))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return &TxnResponse{}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h txnkvHandler) handlerFunc(f func(map[string]string, *TxnRequest) (*TxnResponse, int, error)) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
sendError(w, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var req TxnRequest
|
||||
if err = json.Unmarshal(data, &req); err != nil {
|
||||
sendError(w, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
res, status, err := f(mux.Vars(r), &req)
|
||||
if err != nil {
|
||||
sendError(w, err, status)
|
||||
return
|
||||
}
|
||||
data, err = json.Marshal(res)
|
||||
if err != nil {
|
||||
sendError(w, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
w.Write(data)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2019 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 proxy
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tikv/client-go/config"
|
||||
"github.com/tikv/client-go/rawkv"
|
||||
)
|
||||
|
||||
// RawKVProxy implements proxy to use rawkv API.
|
||||
// It is safe to copy by value or access concurrently.
|
||||
type RawKVProxy struct {
|
||||
clients *sync.Map
|
||||
}
|
||||
|
||||
// NewRaw creates a RawKVProxy instance.
|
||||
func NewRaw() RawKVProxy {
|
||||
return RawKVProxy{
|
||||
clients: &sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new client and returns the client's UUID.
|
||||
func (p RawKVProxy) New(pdAddrs []string, security config.Security) (UUID, error) {
|
||||
client, err := rawkv.NewClient(pdAddrs, security)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return insertWithRetry(p.clients, client), nil
|
||||
}
|
||||
|
||||
// Close releases a rawkv client.
|
||||
func (p RawKVProxy) Close(id UUID) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
if err := client.(*rawkv.Client).Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
p.clients.Delete(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get queries value with the key.
|
||||
func (p RawKVProxy) Get(id UUID, key []byte) ([]byte, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).Get(key)
|
||||
}
|
||||
|
||||
// BatchGet queries values with the keys.
|
||||
func (p RawKVProxy) BatchGet(id UUID, keys [][]byte) ([][]byte, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).BatchGet(keys)
|
||||
}
|
||||
|
||||
// Put stores a key-value pair to TiKV.
|
||||
func (p RawKVProxy) Put(id UUID, key, value []byte) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).Put(key, value)
|
||||
}
|
||||
|
||||
// BatchPut stores key-value pairs to TiKV.
|
||||
func (p RawKVProxy) BatchPut(id UUID, keys, values [][]byte) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).BatchPut(keys, values)
|
||||
}
|
||||
|
||||
// Delete deletes a key-value pair from TiKV.
|
||||
func (p RawKVProxy) Delete(id UUID, key []byte) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).Delete(key)
|
||||
}
|
||||
|
||||
// BatchDelete deletes key-value pairs from TiKV.
|
||||
func (p RawKVProxy) BatchDelete(id UUID, keys [][]byte) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).BatchDelete(keys)
|
||||
}
|
||||
|
||||
// DeleteRange deletes all key-value pairs in a range from TiKV.
|
||||
func (p RawKVProxy) DeleteRange(id UUID, startKey []byte, endKey []byte) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).DeleteRange(startKey, endKey)
|
||||
}
|
||||
|
||||
// Scan queries continuous kv pairs in range [startKey, endKey), up to limit pairs.
|
||||
func (p RawKVProxy) Scan(id UUID, startKey, endKey []byte, limit int) ([][]byte, [][]byte, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return nil, nil, errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*rawkv.Client).Scan(startKey, endKey, limit)
|
||||
}
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
// Copyright 2019 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 proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tikv/client-go/config"
|
||||
"github.com/tikv/client-go/key"
|
||||
"github.com/tikv/client-go/txnkv"
|
||||
"github.com/tikv/client-go/txnkv/kv"
|
||||
)
|
||||
|
||||
// TxnKVProxy implements proxy to use txnkv API.
|
||||
// It is safe to copy by value or access concurrently.
|
||||
type TxnKVProxy struct {
|
||||
clients *sync.Map
|
||||
txns *sync.Map
|
||||
iterators *sync.Map
|
||||
}
|
||||
|
||||
// NewTxn creates a TxnKVProxy instance.
|
||||
func NewTxn() TxnKVProxy {
|
||||
return TxnKVProxy{
|
||||
clients: &sync.Map{},
|
||||
txns: &sync.Map{},
|
||||
iterators: &sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new client and returns the client's UUID.
|
||||
func (p TxnKVProxy) New(pdAddrs []string, security config.Security) (UUID, error) {
|
||||
client, err := txnkv.NewClient(pdAddrs, security)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return insertWithRetry(p.clients, client), nil
|
||||
}
|
||||
|
||||
// Close releases a txnkv client.
|
||||
func (p TxnKVProxy) Close(id UUID) error {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
if err := client.(*txnkv.Client).Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
p.clients.Delete(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Begin starts a new transaction and returns its UUID.
|
||||
func (p TxnKVProxy) Begin(id UUID) (UUID, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return "", errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
txn, err := client.(*txnkv.Client).Begin()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return insertWithRetry(p.txns, txn), nil
|
||||
}
|
||||
|
||||
// BeginWithTS starts a new transaction with given ts and returns its UUID.
|
||||
func (p TxnKVProxy) BeginWithTS(id UUID, ts uint64) (UUID, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return "", errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return insertWithRetry(p.txns, client.(*txnkv.Client).BeginWithTS(ts)), nil
|
||||
}
|
||||
|
||||
// GetTS returns a latest timestamp.
|
||||
func (p TxnKVProxy) GetTS(id UUID) (uint64, error) {
|
||||
client, ok := p.clients.Load(id)
|
||||
if !ok {
|
||||
return 0, errors.WithStack(ErrClientNotFound)
|
||||
}
|
||||
return client.(*txnkv.Client).GetTS()
|
||||
}
|
||||
|
||||
// TxnGet queries value for the given key from TiKV server.
|
||||
func (p TxnKVProxy) TxnGet(id UUID, key []byte) ([]byte, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Get(key)
|
||||
}
|
||||
|
||||
// TxnBatchGet gets a batch of values from TiKV server.
|
||||
func (p TxnKVProxy) TxnBatchGet(id UUID, keys [][]byte) (map[string][]byte, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
ks := *(*[]key.Key)(unsafe.Pointer(&keys))
|
||||
return txn.(*txnkv.Transaction).BatchGet(ks)
|
||||
}
|
||||
|
||||
// TxnSet sets the value for key k as v into TiKV server.
|
||||
func (p TxnKVProxy) TxnSet(id UUID, k []byte, v []byte) error {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Set(k, v)
|
||||
}
|
||||
|
||||
// TxnIter creates an Iterator positioned on the first entry that key <= entry's
|
||||
// key and returns the Iterator's UUID.
|
||||
func (p TxnKVProxy) TxnIter(id UUID, key []byte, upperBound []byte) (UUID, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return "", errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
iter, err := txn.(*txnkv.Transaction).Iter(key, upperBound)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return insertWithRetry(p.iterators, iter), nil
|
||||
}
|
||||
|
||||
// TxnIterReverse creates a reversed Iterator positioned on the first entry
|
||||
// which key is less than key and returns the Iterator's UUID.
|
||||
func (p TxnKVProxy) TxnIterReverse(id UUID, key []byte) (UUID, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return "", errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
iter, err := txn.(*txnkv.Transaction).IterReverse(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return insertWithRetry(p.iterators, iter), nil
|
||||
}
|
||||
|
||||
// TxnIsReadOnly returns if there are pending key-value to commit in the transaction.
|
||||
func (p TxnKVProxy) TxnIsReadOnly(id UUID) (bool, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return false, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).IsReadOnly(), nil
|
||||
}
|
||||
|
||||
// TxnDelete removes the entry for key from TiKV server.
|
||||
func (p TxnKVProxy) TxnDelete(id UUID, key []byte) error {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Delete(key)
|
||||
}
|
||||
|
||||
// TxnCommit commits the transaction operations to TiKV server.
|
||||
func (p TxnKVProxy) TxnCommit(id UUID) error {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
defer p.txns.Delete(id)
|
||||
return txn.(*txnkv.Transaction).Commit(context.Background())
|
||||
}
|
||||
|
||||
// TxnRollback undoes the transaction operations to TiKV server.
|
||||
func (p TxnKVProxy) TxnRollback(id UUID) error {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
defer p.txns.Delete(id)
|
||||
return txn.(*txnkv.Transaction).Rollback()
|
||||
}
|
||||
|
||||
// TxnLockKeys tries to lock the entries with the keys in TiKV server.
|
||||
func (p TxnKVProxy) TxnLockKeys(id UUID, keys [][]byte) error {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
ks := *(*[]key.Key)(unsafe.Pointer(&keys))
|
||||
return txn.(*txnkv.Transaction).LockKeys(ks...)
|
||||
}
|
||||
|
||||
// TxnValid returns if the transaction is valid.
|
||||
func (p TxnKVProxy) TxnValid(id UUID) (bool, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return false, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Valid(), nil
|
||||
}
|
||||
|
||||
// TxnLen returns the count of key-value pairs in the transaction's memory buffer.
|
||||
func (p TxnKVProxy) TxnLen(id UUID) (int, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return 0, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Len(), nil
|
||||
}
|
||||
|
||||
// TxnSize returns the length (in bytes) of the transaction's memory buffer.
|
||||
func (p TxnKVProxy) TxnSize(id UUID) (int, error) {
|
||||
txn, ok := p.txns.Load(id)
|
||||
if !ok {
|
||||
return 0, errors.WithStack(ErrTxnNotFound)
|
||||
}
|
||||
return txn.(*txnkv.Transaction).Size(), nil
|
||||
}
|
||||
|
||||
// IterValid returns if the iterator is valid to use.
|
||||
func (p TxnKVProxy) IterValid(id UUID) (bool, error) {
|
||||
iter, ok := p.iterators.Load(id)
|
||||
if !ok {
|
||||
return false, errors.WithStack(ErrIterNotFound)
|
||||
}
|
||||
return iter.(kv.Iterator).Valid(), nil
|
||||
}
|
||||
|
||||
// IterKey returns the key which the iterator points to.
|
||||
func (p TxnKVProxy) IterKey(id UUID) ([]byte, error) {
|
||||
iter, ok := p.iterators.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrIterNotFound)
|
||||
}
|
||||
return iter.(kv.Iterator).Key(), nil
|
||||
}
|
||||
|
||||
// IterValue returns the value which the iterator points to.
|
||||
func (p TxnKVProxy) IterValue(id UUID) ([]byte, error) {
|
||||
iter, ok := p.iterators.Load(id)
|
||||
if !ok {
|
||||
return nil, errors.WithStack(ErrIterNotFound)
|
||||
}
|
||||
return iter.(kv.Iterator).Value(), nil
|
||||
}
|
||||
|
||||
// IterNext moves the iterator to next entry.
|
||||
func (p TxnKVProxy) IterNext(id UUID) error {
|
||||
iter, ok := p.iterators.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrIterNotFound)
|
||||
}
|
||||
return iter.(kv.Iterator).Next()
|
||||
}
|
||||
|
||||
// IterClose releases an iterator.
|
||||
func (p TxnKVProxy) IterClose(id UUID) error {
|
||||
iter, ok := p.iterators.Load(id)
|
||||
if !ok {
|
||||
return errors.WithStack(ErrIterNotFound)
|
||||
}
|
||||
iter.(kv.Iterator).Close()
|
||||
p.iterators.Delete(id)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2019 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 proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Proxy errors. Use errors.Cause() to determine error type.
|
||||
var (
|
||||
ErrClientNotFound = errors.New("client not found")
|
||||
ErrTxnNotFound = errors.New("txn not found")
|
||||
ErrIterNotFound = errors.New("iterator not found")
|
||||
)
|
||||
|
||||
// UUID is a global unique ID to identify clients, transactions, or iterators.
|
||||
type UUID string
|
||||
|
||||
func insertWithRetry(m *sync.Map, d interface{}) UUID {
|
||||
for {
|
||||
id := UUID(uuid.New().String())
|
||||
if _, hasOld := m.LoadOrStore(id, d); !hasOld {
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -205,7 +205,7 @@ func (c *Client) Delete(key []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// BatchDelete deletes key-value pairs from TiKV
|
||||
// BatchDelete deletes key-value pairs from TiKV.
|
||||
func (c *Client) BatchDelete(keys [][]byte) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue