Browse Source
Merge pull request #4 from chrislusf/master
Merge pull request #4 from chrislusf/master
Syncing to the original repositorypull/2025/head
bingoohuang
5 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
253 changed files with 14128 additions and 3276 deletions
-
5.github/ISSUE_TEMPLATE/bug_report.md
-
8.travis.yml
-
2Makefile
-
8README.md
-
1backers.md
-
2docker/dev-compose.yml
-
2docker/entrypoint.sh
-
2docker/seaweedfs-compose.yml
-
99go.mod
-
776go.sum
-
20other/java/client/pom.xml
-
32other/java/client/src/main/java/seaweedfs/client/FilerClient.java
-
46other/java/client/src/main/java/seaweedfs/client/FilerGrpcClient.java
-
64other/java/client/src/main/java/seaweedfs/client/FilerSslContext.java
-
25other/java/client/src/main/java/seaweedfs/client/SeaweedRead.java
-
12other/java/client/src/main/java/seaweedfs/client/SeaweedWrite.java
-
5other/java/client/src/main/proto/filer.proto
-
23other/java/client/src/test/java/seaweedfs/client/SeaweedFilerTest.java
-
133other/java/hdfs2/dependency-reduced-pom.xml
-
163other/java/hdfs2/pom.xml
-
0other/java/hdfs2/src/main/java/seaweed/hdfs/ReadBuffer.java
-
0other/java/hdfs2/src/main/java/seaweed/hdfs/ReadBufferManager.java
-
0other/java/hdfs2/src/main/java/seaweed/hdfs/ReadBufferStatus.java
-
0other/java/hdfs2/src/main/java/seaweed/hdfs/ReadBufferWorker.java
-
51other/java/hdfs2/src/main/java/seaweed/hdfs/SeaweedFileSystem.java
-
19other/java/hdfs2/src/main/java/seaweed/hdfs/SeaweedFileSystemStore.java
-
0other/java/hdfs2/src/main/java/seaweed/hdfs/SeaweedInputStream.java
-
283other/java/hdfs2/src/main/java/seaweed/hdfs/SeaweedOutputStream.java
-
133other/java/hdfs3/dependency-reduced-pom.xml
-
8other/java/hdfs3/pom.xml
-
137other/java/hdfs3/src/main/java/seaweed/hdfs/ReadBuffer.java
-
394other/java/hdfs3/src/main/java/seaweed/hdfs/ReadBufferManager.java
-
29other/java/hdfs3/src/main/java/seaweed/hdfs/ReadBufferStatus.java
-
70other/java/hdfs3/src/main/java/seaweed/hdfs/ReadBufferWorker.java
-
620other/java/hdfs3/src/main/java/seaweed/hdfs/SeaweedFileSystem.java
-
270other/java/hdfs3/src/main/java/seaweed/hdfs/SeaweedFileSystemStore.java
-
371other/java/hdfs3/src/main/java/seaweed/hdfs/SeaweedInputStream.java
-
0other/java/hdfs3/src/main/java/seaweed/hdfs/SeaweedOutputStream.java
-
10unmaintained/change_superblock/change_superblock.go
-
27unmaintained/fix_dat/fix_dat.go
-
13unmaintained/load_test/load_test_leveldb/load_test_leveldb.go
-
95unmaintained/remove_duplicate_fids/remove_duplicate_fids.go
-
11unmaintained/see_dat/see_dat.go
-
66weed/command/backup.go
-
2weed/command/benchmark.go
-
7weed/command/compact.go
-
24weed/command/export.go
-
118weed/command/filer_copy.go
-
17weed/command/fix.go
-
80weed/command/master.go
-
10weed/command/mount.go
-
13weed/command/mount_darwin.go
-
13weed/command/mount_freebsd.go
-
157weed/command/mount_linux.go
-
1weed/command/mount_notsupported.go
-
42weed/command/mount_std.go
-
56weed/command/scaffold.go
-
44weed/command/scaffold_test.go
-
77weed/command/server.go
-
17weed/command/shell.go
-
146weed/command/volume.go
-
84weed/command/weedfuse/README.md
-
109weed/command/weedfuse/weedfuse.go
-
30weed/filer2/abstract_sql/abstract_sql_store.go
-
11weed/filer2/cassandra/cassandra_store.go
-
2weed/filer2/entry.go
-
27weed/filer2/entry_codec.go
-
196weed/filer2/etcd/etcd_store.go
-
72weed/filer2/filer.go
-
57weed/filer2/filer_client_util.go
-
102weed/filer2/filer_delete_entry.go
-
9weed/filer2/filer_deletion.go
-
14weed/filer2/filerstore.go
-
35weed/filer2/leveldb/leveldb_store.go
-
41weed/filer2/leveldb2/leveldb2_store.go
-
4weed/filer2/leveldb2/leveldb2_store_test.go
-
132weed/filer2/memdb/memdb_store.go
-
149weed/filer2/memdb/memdb_store_test.go
-
9weed/filer2/mysql/mysql_store.go
-
1weed/filer2/postgres/postgres_store.go
-
14weed/filer2/redis/redis_cluster_store.go
-
18weed/filer2/redis/universal_redis_store.go
-
251weed/filer2/tikv/tikv_store.go
-
65weed/filer2/tikv/tikv_store_unsupported.go
-
248weed/filesys/dir.go
-
4weed/filesys/dir_link.go
-
2weed/filesys/dirty_page.go
-
144weed/filesys/file.go
-
13weed/filesys/filehandle.go
-
10weed/filesys/wfs.go
-
142weed/filesys/xattr.go
-
117weed/glide.yaml
-
6weed/notification/aws_sqs/aws_sqs_pub.go
-
2weed/notification/kafka/kafka_queue.go
-
30weed/operation/assign_file_id.go
-
2weed/operation/delete_content.go
-
2weed/operation/submit.go
-
5weed/pb/filer.proto
-
300weed/pb/filer_pb/filer.pb.go
-
20weed/pb/master.proto
@ -0,0 +1,99 @@ |
|||
module github.com/chrislusf/seaweedfs |
|||
|
|||
go 1.12 |
|||
|
|||
require ( |
|||
cloud.google.com/go v0.44.3 |
|||
github.com/Azure/azure-pipeline-go v0.2.2 // indirect |
|||
github.com/Azure/azure-storage-blob-go v0.8.0 |
|||
github.com/DataDog/zstd v1.4.1 // indirect |
|||
github.com/Shopify/sarama v1.23.1 |
|||
github.com/aws/aws-sdk-go v1.23.13 |
|||
github.com/chrislusf/raft v0.0.0-20190225081310-10d6e2182d92 |
|||
github.com/coreos/etcd v3.3.15+incompatible // indirect |
|||
github.com/coreos/go-semver v0.3.0 // indirect |
|||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect |
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible |
|||
github.com/disintegration/imaging v1.6.1 |
|||
github.com/dustin/go-humanize v1.0.0 |
|||
github.com/eapache/go-resiliency v1.2.0 // indirect |
|||
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a |
|||
github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 |
|||
github.com/frankban/quicktest v1.7.2 // indirect |
|||
github.com/gabriel-vasile/mimetype v1.0.0 |
|||
github.com/go-redis/redis v6.15.2+incompatible |
|||
github.com/go-sql-driver/mysql v1.4.1 |
|||
github.com/gocql/gocql v0.0.0-20190829130954-e163eff7a8c6 |
|||
github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48 // indirect |
|||
github.com/golang/protobuf v1.3.2 |
|||
github.com/google/btree v1.0.0 |
|||
github.com/google/uuid v1.1.1 |
|||
github.com/gorilla/mux v1.7.3 |
|||
github.com/gorilla/websocket v1.4.1 // indirect |
|||
github.com/grpc-ecosystem/grpc-gateway v1.11.0 // indirect |
|||
github.com/hashicorp/golang-lru v0.5.3 // indirect |
|||
github.com/jacobsa/daemonize v0.0.0-20160101105449-e460293e890f |
|||
github.com/jcmturner/gofork v1.0.0 // indirect |
|||
github.com/karlseguin/ccache v2.0.3+incompatible |
|||
github.com/karlseguin/expect v1.0.1 // indirect |
|||
github.com/klauspost/cpuid v1.2.1 // indirect |
|||
github.com/klauspost/crc32 v1.2.0 |
|||
github.com/klauspost/reedsolomon v1.9.2 |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect |
|||
github.com/kurin/blazer v0.5.3 |
|||
github.com/lib/pq v1.2.0 |
|||
github.com/magiconair/properties v1.8.1 // indirect |
|||
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb // indirect |
|||
github.com/mattn/go-runewidth v0.0.4 // indirect |
|||
github.com/nats-io/nats-server/v2 v2.0.4 // indirect |
|||
github.com/onsi/ginkgo v1.10.1 // indirect |
|||
github.com/onsi/gomega v1.7.0 // indirect |
|||
github.com/opentracing/opentracing-go v1.1.0 // indirect |
|||
github.com/pelletier/go-toml v1.4.0 // indirect |
|||
github.com/peterh/liner v1.1.0 |
|||
github.com/pierrec/lz4 v2.2.7+incompatible // indirect |
|||
github.com/pingcap/kvproto v0.0.0-20191022073741-81b2a2d9e986 // indirect |
|||
github.com/pingcap/tidb v1.1.0-beta.0.20191023070859-58fc7d44f73b |
|||
github.com/pingcap/tipb v0.0.0-20191022094114-a2e8c3fa634b // indirect |
|||
github.com/prometheus/client_golang v1.1.0 |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect |
|||
github.com/prometheus/procfs v0.0.4 // indirect |
|||
github.com/rakyll/statik v0.1.6 |
|||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect |
|||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 // indirect |
|||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd |
|||
github.com/seaweedfs/fuse v0.0.0-20190510212405-310228904eff |
|||
github.com/sirupsen/logrus v1.4.2 // indirect |
|||
github.com/spaolacci/murmur3 v1.1.0 // indirect |
|||
github.com/spf13/afero v1.2.2 // indirect |
|||
github.com/spf13/jwalterweatherman v1.1.0 // indirect |
|||
github.com/spf13/viper v1.4.0 |
|||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 // indirect |
|||
github.com/stretchr/testify v1.4.0 // indirect |
|||
github.com/syndtr/goleveldb v1.0.0 |
|||
github.com/tidwall/gjson v1.3.2 |
|||
github.com/tidwall/match v1.0.1 |
|||
github.com/uber-go/atomic v1.4.0 // indirect |
|||
github.com/uber/jaeger-client-go v2.17.0+incompatible // indirect |
|||
github.com/uber/jaeger-lib v2.0.0+incompatible // indirect |
|||
github.com/willf/bitset v1.1.10 // indirect |
|||
github.com/willf/bloom v2.0.3+incompatible |
|||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 // indirect |
|||
go.etcd.io/etcd v3.3.15+incompatible |
|||
gocloud.dev v0.16.0 |
|||
gocloud.dev/pubsub/natspubsub v0.16.0 |
|||
gocloud.dev/pubsub/rabbitpubsub v0.16.0 |
|||
golang.org/x/image v0.0.0-20190829233526-b3c06291d021 // indirect |
|||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b |
|||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b |
|||
golang.org/x/tools v0.0.0-20190911022129-16c5e0f7d110 |
|||
google.golang.org/api v0.9.0 |
|||
google.golang.org/appengine v1.6.2 // indirect |
|||
google.golang.org/grpc v1.23.0 |
|||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect |
|||
gopkg.in/jcmturner/gokrb5.v7 v7.3.0 // indirect |
|||
gopkg.in/karlseguin/expect.v1 v1.0.1 // indirect |
|||
sigs.k8s.io/yaml v1.1.0 // indirect |
|||
) |
|||
|
|||
replace github.com/satori/go.uuid v1.2.0 => github.com/satori/go.uuid v0.0.0-20181028125025-b2ce2384e17b |
@ -0,0 +1,776 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= |
|||
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= |
|||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= |
|||
cloud.google.com/go v0.44.3 h1:0sMegbmn/8uTwpNkB0q9cLEpZ2W5a6kl+wtBQgPWBJQ= |
|||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= |
|||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= |
|||
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= |
|||
contrib.go.opencensus.io/exporter/ocagent v0.5.0 h1:TKXjQSRS0/cCDrP7KvkgU6SmILtF/yV2TOs/02K/WZQ= |
|||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= |
|||
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= |
|||
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= |
|||
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= |
|||
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= |
|||
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= |
|||
github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= |
|||
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo= |
|||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= |
|||
github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY= |
|||
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= |
|||
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= |
|||
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= |
|||
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= |
|||
github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= |
|||
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o= |
|||
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= |
|||
github.com/Azure/go-autorest v12.0.0+incompatible h1:N+VqClcomLGD/sHb3smbSYYtNMgKpVV3Cd5r5i8z6bQ= |
|||
github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= |
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= |
|||
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 h1:2T/jmrHeTezcCM58lvEQXs0UpQJCo5SoGAcg+mbSTIg= |
|||
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= |
|||
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= |
|||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= |
|||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190605020000-c4ba1fdf4d36/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= |
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= |
|||
github.com/Shopify/sarama v1.23.1 h1:XxJBCZEoWJtoWjf/xRbmGUpAmTZGnuuF0ON0EvxxBrs= |
|||
github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= |
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= |
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= |
|||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f h1:5ZfJxyXo8KyX8DgGXC5B7ILL8y51fci/qYz2B4j8iLY= |
|||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= |
|||
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= |
|||
github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= |
|||
github.com/aws/aws-sdk-go v1.23.13 h1:l/NG+mgQFRGG3dsFzEj0jw9JIs/zYdtU6MXhY1WIDmM= |
|||
github.com/aws/aws-sdk-go v1.23.13/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= |
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= |
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= |
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= |
|||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= |
|||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= |
|||
github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= |
|||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= |
|||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= |
|||
github.com/chrislusf/raft v0.0.0-20190225081310-10d6e2182d92 h1:lM9SFsh0EPXkyJyrTJqLZPAIJBtNFP6LNkYXu2MnSZI= |
|||
github.com/chrislusf/raft v0.0.0-20190225081310-10d6e2182d92/go.mod h1:4jyiUCD5y548+yKW+oiHtccBiMaLCCbFBpK2t7X4eUo= |
|||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= |
|||
github.com/chzyer/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= |
|||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= |
|||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= |
|||
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= |
|||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= |
|||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= |
|||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= |
|||
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/etcd v3.3.15+incompatible h1:+9RjdC18gMxNQVvSiXvObLu29mOFmkgdsB4cRTlV+EE= |
|||
github.com/coreos/etcd v3.3.15+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-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= |
|||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= |
|||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= |
|||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f 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/cznic/sortutil v0.0.0-20150617083342-4c7342852e65 h1:hxuZop6tSoOi0sxFzoGGYdRqNrPubyaIf9KoBG9tPiE= |
|||
github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= |
|||
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/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= |
|||
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/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f h1:dDxpBYafY/GYpcl+LS4Bn3ziLPuEdGRkRjYAbSlWxSA= |
|||
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= |
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= |
|||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= |
|||
github.com/disintegration/imaging v1.6.1 h1:JnBbK6ECIZb1NsWIikP9pd8gIlTIRx7fuDNpU9fsxOE= |
|||
github.com/disintegration/imaging v1.6.1/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= |
|||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
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/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU= |
|||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= |
|||
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= |
|||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= |
|||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= |
|||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= |
|||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= |
|||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= |
|||
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/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= |
|||
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= |
|||
github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 h1:0YtRCqIZs2+Tz49QuH6cJVw/IFqzo39gEqZ0iYLxD2M= |
|||
github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4/go.mod h1:vsJz7uE339KUCpBXx3JAJzSRH7Uk4iGGyJzR529qDIA= |
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= |
|||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= |
|||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= |
|||
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk= |
|||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= |
|||
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/gabriel-vasile/mimetype v0.3.17 h1:NGWgggJJqTofUcTV1E7hkk2zVjZ54EfJa1z5O3z6By4= |
|||
github.com/gabriel-vasile/mimetype v0.3.17/go.mod h1:kMJbg3SlWZCsj4R73F1WDzbT9AyGCOVmUtIxxwO5pmI= |
|||
github.com/gabriel-vasile/mimetype v1.0.0 h1:0QKnAQQhG6oOsb4GK7iPlet7RtjHi9us8RF/nXoTxhI= |
|||
github.com/gabriel-vasile/mimetype v1.0.0/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= |
|||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= |
|||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= |
|||
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= |
|||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= |
|||
github.com/go-playground/overalls v0.0.0-20180201144345-22ec1a223b7c/go.mod h1:UqxAgEOt89sCiXlrc/ycnx00LVvUO/eS8tMUkWX4R7w= |
|||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= |
|||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= |
|||
github.com/go-sql-driver/mysql v0.0.0-20170715192408-3955978caca4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= |
|||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= |
|||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gocql/gocql v0.0.0-20190829130954-e163eff7a8c6 h1:P66kRWyEoIx6URKgAC3ijx9jo9gEid7bEhLQ/Z0G65A= |
|||
github.com/gocql/gocql v0.0.0-20190829130954-e163eff7a8c6/go.mod h1:Q7Sru5153KG8D9zwueuQJB3ccJf9/bIwF/x8b3oKgT8= |
|||
github.com/gogo/protobuf v0.0.0-20180717141946-636bf0302bc9/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= |
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= |
|||
github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48 h1:X+zN6RZXsvnrSJaAIQhZezPfAfvsqihKKR8oiLHid34= |
|||
github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
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/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= |
|||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= |
|||
github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
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-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= |
|||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-replayers/grpcreplay v0.1.0 h1:eNb1y9rZFmY4ax45uEEECSa8fsxGRU+8Bil52ASAwic= |
|||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= |
|||
github.com/google/go-replayers/httpreplay v0.1.0 h1:AX7FUb4BjrrzNvblr/OlgwrmFiep6soj5K2QSDW7BGk= |
|||
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= |
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE= |
|||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= |
|||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= |
|||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60= |
|||
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= |
|||
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww= |
|||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= |
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= |
|||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= |
|||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= |
|||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= |
|||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= |
|||
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
|||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
|||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= |
|||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
|||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= |
|||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= |
|||
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/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= |
|||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
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-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= |
|||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/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.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.11.0 h1:aT5ISUniaOTErogCQ+4pGoYNBB6rm6Fq3g1v8QwYGas= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.11.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= |
|||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= |
|||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= |
|||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= |
|||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= |
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= |
|||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/jacobsa/daemonize v0.0.0-20160101105449-e460293e890f h1:X+tnaqoCcBgAwSTJtoYW6p0qKiuPyMfofEHEFUf2kdU= |
|||
github.com/jacobsa/daemonize v0.0.0-20160101105449-e460293e890f/go.mod h1:Ip4fOwzCrnDVuluHBd7FXIMb7SHOKfkt9/UDrYSZvqI= |
|||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03 h1:FUwcHNlEqkqLjLBdCp5PRlCFijNjvcYANOZXzCfXwCM= |
|||
github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= |
|||
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= |
|||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= |
|||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= |
|||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= |
|||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= |
|||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= |
|||
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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= |
|||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY= |
|||
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/karlseguin/ccache v2.0.3+incompatible h1:j68C9tWOROiOLWTS/kCGg9IcJG+ACqn5+0+t8Oh83UU= |
|||
github.com/karlseguin/ccache v2.0.3+incompatible/go.mod h1:CM9tNPzT6EdRh14+jiW8mEF9mkNZuuE51qmgGYUB93w= |
|||
github.com/karlseguin/expect v1.0.1 h1:z4wy4npwwHSWKjGWH85WNJO42VQhovxTCZDSzhjo8hY= |
|||
github.com/karlseguin/expect v1.0.1/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= |
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= |
|||
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= |
|||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= |
|||
github.com/klauspost/crc32 v1.2.0 h1:0VuyqOCruD33/lJ/ojXNvzVyl8Zr5zdTmj9l9qLZ86I= |
|||
github.com/klauspost/crc32 v1.2.0/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= |
|||
github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18= |
|||
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= |
|||
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/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
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.0.0/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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/kurin/blazer v0.5.3 h1:SAgYv0TKU0kN/ETfO5ExjNAPyMt2FocO2s/UlCHfjAk= |
|||
github.com/kurin/blazer v0.5.3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU= |
|||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= |
|||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= |
|||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
|||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= |
|||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA= |
|||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= |
|||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= |
|||
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb h1:hXqqXzQtJbENrsb+rsIqkVqcg4FUJL0SQFGw08Dgivw= |
|||
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= |
|||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
|||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= |
|||
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= |
|||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= |
|||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= |
|||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= |
|||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
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/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= |
|||
github.com/montanaflynn/stats v0.0.0-20180911141734-db72e6cae808 h1:pmpDGKLw4n82EtrNiLqB+xSz/JQwFOaZuMALYUHwX5s= |
|||
github.com/montanaflynn/stats v0.0.0-20180911141734-db72e6cae808/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/nats-io/jwt v0.2.6/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= |
|||
github.com/nats-io/jwt v0.2.14 h1:wA50KvFz/JXGXMHRygTWsRGh/ixxgC5E3kHvmtGLNf4= |
|||
github.com/nats-io/jwt v0.2.14/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= |
|||
github.com/nats-io/nats-server/v2 v2.0.0/go.mod h1:RyVdsHHvY4B6c9pWG+uRLpZ0h0XsqiuKp2XCTurP5LI= |
|||
github.com/nats-io/nats-server/v2 v2.0.4 h1:XOMeQRbhl1lGNTIctPhih6pTa15NGif54Uas6ZW5q7g= |
|||
github.com/nats-io/nats-server/v2 v2.0.4/go.mod h1:AWdGEVbjKRS9ZIx4DSP5eKW48nfFm7q3uiSkP/1KD7M= |
|||
github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= |
|||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= |
|||
github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M= |
|||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= |
|||
github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= |
|||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= |
|||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= |
|||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= |
|||
github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7 h1:7KAv7KMGTTqSmYZtNdcNTgsos+vFzULLwyElndwn+5c= |
|||
github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7/go.mod h1:iWMfgwqYW+e8n5lC/jjNEhwcjbRDpl5NT7n2h+4UNcI= |
|||
github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef h1:K0Fn+DoFqNqktdZtdV3bPQ/0cuYh2H4rkg0tytX/07k= |
|||
github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef/go.mod h1:7WjlapSfwQyo6LNmIvEWzsW1hbBQfpUO4JWnuQRmva8= |
|||
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= |
|||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= |
|||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= |
|||
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/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= |
|||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
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/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= |
|||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= |
|||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= |
|||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= |
|||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= |
|||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= |
|||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= |
|||
github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os= |
|||
github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= |
|||
github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= |
|||
github.com/pierrec/lz4 v2.2.7+incompatible h1:Eerk9aiqeZo2QzsbWOAsELUf9ddvAxEdMY9LYze/DEc= |
|||
github.com/pierrec/lz4 v2.2.7+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= |
|||
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/errcode v0.0.0-20180921232412-a1a7271709d9 h1:KH4f4Si9XK6/IW50HtoaiLIFHGkapOM6w83za47UYik= |
|||
github.com/pingcap/errcode v0.0.0-20180921232412-a1a7271709d9/go.mod h1:4b2X8xSqxIroj/IZ9MX/VGZhAwc11wB9wRIzHvz6SeM= |
|||
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= |
|||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= |
|||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= |
|||
github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7xvRV6DzvPkKY4QXzfVbjU1BhW0d9yL8= |
|||
github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= |
|||
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-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= |
|||
github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= |
|||
github.com/pingcap/kvproto v0.0.0-20191022073741-81b2a2d9e986 h1:XFh7n8Cheo00pakfhpUofnlptHCuz9lkp4p/jXPb8lM= |
|||
github.com/pingcap/kvproto v0.0.0-20191022073741-81b2a2d9e986/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= |
|||
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= |
|||
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= |
|||
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= |
|||
github.com/pingcap/parser v0.0.0-20191021083151-7c64f78a5100 h1:TRyps2d+2TsJv1Vk4S2D+5COMDVKClnAO5aNmGGVyj0= |
|||
github.com/pingcap/parser v0.0.0-20191021083151-7c64f78a5100/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= |
|||
github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 h1:GIEq+wZfrl2bcJxpuSrEH4H7/nlf5YdmpS+dU9lNIt8= |
|||
github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0/go.mod h1:G/6rJpnYwM0LKMec2rI82/5Kg6GaZMvlfB+e6/tvYmI= |
|||
github.com/pingcap/tidb v1.1.0-beta.0.20191023070859-58fc7d44f73b h1:6GfcYOX9/CCxPnNOivVxiDYXbZrCHU1mRp691iw9EYs= |
|||
github.com/pingcap/tidb v1.1.0-beta.0.20191023070859-58fc7d44f73b/go.mod h1:YfrHdQ613A+E2FSugyXOdJmeZQbXNjpXX2doNe8MGj8= |
|||
github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible h1:MkWCxgZpJBgY2f4HtwWMMFzSBb3+JPzeJgF3VrXE/bU= |
|||
github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= |
|||
github.com/pingcap/tipb v0.0.0-20191015023537-709b39e7f8bb/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI= |
|||
github.com/pingcap/tipb v0.0.0-20191022094114-a2e8c3fa634b h1:DZ0cTsn4lGMNaRjkUFKBtHn4s2F8KFMm83lWvSo+x7c= |
|||
github.com/pingcap/tipb v0.0.0-20191022094114-a2e8c3fa634b/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= |
|||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= |
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= |
|||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= |
|||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= |
|||
github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= |
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= |
|||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= |
|||
github.com/prometheus/procfs v0.0.0-20180612222113-7d6f385de8be/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= |
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= |
|||
github.com/prometheus/procfs v0.0.4 h1:w8DjqFMJDjuVwdZBQoOozr4MVWOnwF7RcL/7uxBjY78= |
|||
github.com/prometheus/procfs v0.0.4/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= |
|||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= |
|||
github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= |
|||
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= |
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= |
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= |
|||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ= |
|||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= |
|||
github.com/remyoudompheng/bigfft v0.0.0-20190512091148-babf20351dd7/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= |
|||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 h1:HQagqIiBmr8YXawX/le3+O26N+vPPC1PtjaF3mwnook= |
|||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= |
|||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= |
|||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= |
|||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= |
|||
github.com/seaweedfs/fuse v0.0.0-20190510212405-310228904eff h1:uLd5zBvf5OA67wcVRePHrFt60bR4LSskaVhgVwyk0Jg= |
|||
github.com/seaweedfs/fuse v0.0.0-20190510212405-310228904eff/go.mod h1:cubdLmQFqEUZ9vNJrznhgc3m3VMAJi/nY2Ix2axXkG0= |
|||
github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= |
|||
github.com/shirou/gopsutil v2.18.10+incompatible h1:cy84jW6EVRPa5g9HAHrlbxMSIjBhDSX0OFYyMYminYs= |
|||
github.com/shirou/gopsutil v2.18.10+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= |
|||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= |
|||
github.com/shurcooL/vfsgen v0.0.0-20181020040650-a97a25d856ca/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= |
|||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= |
|||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= |
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= |
|||
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/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= |
|||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= |
|||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= |
|||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= |
|||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= |
|||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= |
|||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= |
|||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= |
|||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 h1:0ngsPmuP6XIjiFRNFYlvKwSr5zff2v+uPHaffZ6/M4k= |
|||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= |
|||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= |
|||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= |
|||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= |
|||
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/struCoder/pidusage v0.1.2/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI= |
|||
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= |
|||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= |
|||
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2/go.mod h1:2PfKggNGDuadAa0LElHrByyrz4JPZ9fFx6Gs7nx7ZZU= |
|||
github.com/tidwall/gjson v1.3.2 h1:+7p3qQFaH3fOMXAJSrdZwGKcOO/lYdGS0HqGhPqDdTI= |
|||
github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= |
|||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= |
|||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= |
|||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= |
|||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= |
|||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= |
|||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= |
|||
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/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= |
|||
github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o= |
|||
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= |
|||
github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= |
|||
github.com/uber/jaeger-client-go v2.17.0+incompatible h1:35tpDuT3k0oBiN/aGoSWuiFaqKgKZSciSMnWrazhSHE= |
|||
github.com/uber/jaeger-client-go v2.17.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= |
|||
github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= |
|||
github.com/uber/jaeger-lib v2.0.0+incompatible h1:iMSCV0rmXEogjNWPh2D0xk9YVKvrtGoHJNe9ebLu/pw= |
|||
github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= |
|||
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= |
|||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= |
|||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= |
|||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= |
|||
github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= |
|||
github.com/unrolled/render v0.0.0-20180914162206-b9786414de4d h1:ggUgChAeyge4NZ4QUw6lhHsVymzwSDJOZcE0s2X8S20= |
|||
github.com/unrolled/render v0.0.0-20180914162206-b9786414de4d/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= |
|||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= |
|||
github.com/urfave/negroni v0.3.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= |
|||
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= |
|||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= |
|||
github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA= |
|||
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8= |
|||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= |
|||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= |
|||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= |
|||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= |
|||
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= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= |
|||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= |
|||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= |
|||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= |
|||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= |
|||
go.etcd.io/etcd v0.0.0-20190320044326-77d4b742cdbf/go.mod h1:KSGwdbiFchh5KIC9My2+ZVl5/3ANcwohw50dpPwa2cw= |
|||
go.etcd.io/etcd v3.3.15+incompatible h1:0VpOVCF6EFnJptt8Jh0EWEHO4j2fepyV1fpu9xz/UoQ= |
|||
go.etcd.io/etcd v3.3.15+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= |
|||
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= |
|||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= |
|||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= |
|||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= |
|||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= |
|||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= |
|||
go.uber.org/atomic v1.4.0/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/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4= |
|||
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= |
|||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= |
|||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= |
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= |
|||
gocloud.dev v0.16.0 h1:hWeaQWxamGerwsU7B9xSWvUjx0p7TwG8fcHro2TzbbM= |
|||
gocloud.dev v0.16.0/go.mod h1:xWGXD8t7bEhqPIuyAUFyXV9qHn+PvEY2F2GKPh7i/O0= |
|||
gocloud.dev/pubsub/natspubsub v0.16.0 h1:MoBGXULDzb1fVaZsGWO5cUCgr6yoI/DHhau8OPGaGEI= |
|||
gocloud.dev/pubsub/natspubsub v0.16.0/go.mod h1:0n7pT7PkLMClBUHDrOkHfOFVr/o/6kawNMwsyAbwadI= |
|||
gocloud.dev/pubsub/rabbitpubsub v0.16.0 h1:Bkv2njMSl2tmT3tGbvbwpiIDAXBIpqzP9dmts+rhD4E= |
|||
gocloud.dev/pubsub/rabbitpubsub v0.16.0/go.mod h1:JJVdUUIqwgaaMJg/1xHQza0g4sI/4KHHSNiGE+pn4JM= |
|||
golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= |
|||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= |
|||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= |
|||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= |
|||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= |
|||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0= |
|||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= |
|||
golang.org/x/image v0.0.0-20190829233526-b3c06291d021 h1:j6QOxNFMpEL1wIQX6TUdBPNfGZKmBOJS/vfSm8a7tdM= |
|||
golang.org/x/image v0.0.0-20190829233526-b3c06291d021/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= |
|||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= |
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc= |
|||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= |
|||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= |
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190909082730-f460065e899a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI= |
|||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= |
|||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20190911022129-16c5e0f7d110 h1:6S6bidS7O4yAwA5ORRbRIjvNQ9tGbLd5e+LRIaTeVDQ= |
|||
golang.org/x/tools v0.0.0-20190911022129-16c5e0f7d110/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= |
|||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= |
|||
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= |
|||
google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM= |
|||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= |
|||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= |
|||
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= |
|||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= |
|||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= |
|||
google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI= |
|||
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= |
|||
google.golang.org/genproto v0.0.0-20180608181217-32ee49c4dd80/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= |
|||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= |
|||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/genproto v0.0.0-20190905072037-92dd089d5514 h1:oFSK4421fpCKRrpzIpybyBVWyht05NegY9+L/3TLAZs= |
|||
google.golang.org/genproto v0.0.0-20190905072037-92dd089d5514/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/grpc v0.0.0-20180607172857-7a6a684ca69e/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= |
|||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= |
|||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= |
|||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= |
|||
gopkg.in/alecthomas/gometalinter.v2 v2.0.12/go.mod h1:NDRytsqEZyolNuAgTzJkZMkSQM7FIKyzVzGhjB/qfYo= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= |
|||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= |
|||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= |
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= |
|||
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= |
|||
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= |
|||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= |
|||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= |
|||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI= |
|||
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= |
|||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3 h1:hHMV/yKPwMnJhPuPx7pH2Uw/3Qyf+thJYlisUc44010= |
|||
gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= |
|||
gopkg.in/jcmturner/gokrb5.v7 v7.3.0 h1:0709Jtq/6QXEuWRfAm260XqlpcwL1vxtO1tUE2qK8Z4= |
|||
gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= |
|||
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= |
|||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= |
|||
gopkg.in/karlseguin/expect.v1 v1.0.1 h1:9u0iUltnhFbJTHaSIH0EP+cuTU5rafIgmcsEsg2JQFw= |
|||
gopkg.in/karlseguin/expect.v1 v1.0.1/go.mod h1:uB7QIJBcclvYbwlUDkSCsGjAOMis3fP280LyhuDEf2I= |
|||
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= |
|||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= |
|||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= |
|||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= |
|||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4 h1:VO9oZbbkvTwqLimlQt15QNdOOBArT2dw/bvzsMZBiqQ= |
|||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= |
|||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k= |
@ -0,0 +1,64 @@ |
|||
package seaweedfs.client; |
|||
|
|||
import com.google.common.base.Strings; |
|||
import com.moandjiezana.toml.Toml; |
|||
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; |
|||
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; |
|||
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; |
|||
import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import javax.net.ssl.SSLException; |
|||
import java.io.File; |
|||
|
|||
public class FilerSslContext { |
|||
|
|||
private static final Logger logger = LoggerFactory.getLogger(FilerSslContext.class); |
|||
|
|||
public static SslContext loadSslContext() throws SSLException { |
|||
String securityFileName = "security.toml"; |
|||
String home = System.getProperty("user.home"); |
|||
File f1 = new File("./"+securityFileName); |
|||
File f2 = new File(home + "/.seaweedfs/"+securityFileName); |
|||
File f3 = new File(home + "/etc/seaweedfs/"+securityFileName); |
|||
|
|||
File securityFile = f1.exists()? f1 : f2.exists() ? f2 : f3.exists()? f3 : null; |
|||
|
|||
if (securityFile==null){ |
|||
return null; |
|||
} |
|||
|
|||
Toml toml = new Toml().read(securityFile); |
|||
logger.debug("reading ssl setup from {}", securityFile); |
|||
|
|||
String trustCertCollectionFilePath = toml.getString("grpc.ca"); |
|||
logger.debug("loading ca from {}", trustCertCollectionFilePath); |
|||
String clientCertChainFilePath = toml.getString("grpc.client.cert"); |
|||
logger.debug("loading client ca from {}", clientCertChainFilePath); |
|||
String clientPrivateKeyFilePath = toml.getString("grpc.client.key"); |
|||
logger.debug("loading client key from {}", clientPrivateKeyFilePath); |
|||
|
|||
if (Strings.isNullOrEmpty(clientPrivateKeyFilePath) && Strings.isNullOrEmpty(clientPrivateKeyFilePath)){ |
|||
return null; |
|||
} |
|||
|
|||
// possibly fix the format https://netty.io/wiki/sslcontextbuilder-and-private-key.html |
|||
|
|||
return buildSslContext(trustCertCollectionFilePath, clientCertChainFilePath, clientPrivateKeyFilePath); |
|||
} |
|||
|
|||
|
|||
private static SslContext buildSslContext(String trustCertCollectionFilePath, |
|||
String clientCertChainFilePath, |
|||
String clientPrivateKeyFilePath) throws SSLException { |
|||
SslContextBuilder builder = GrpcSslContexts.forClient(); |
|||
if (trustCertCollectionFilePath != null) { |
|||
builder.trustManager(new File(trustCertCollectionFilePath)); |
|||
} |
|||
if (clientCertChainFilePath != null && clientPrivateKeyFilePath != null) { |
|||
builder.keyManager(new File(clientCertChainFilePath), new File(clientPrivateKeyFilePath)); |
|||
} |
|||
return builder.trustManager(InsecureTrustManagerFactory.INSTANCE).build(); |
|||
} |
|||
} |
@ -0,0 +1,23 @@ |
|||
package seaweedfs.client; |
|||
|
|||
import java.util.List; |
|||
|
|||
public class SeaweedFilerTest { |
|||
public static void main(String[] args){ |
|||
|
|||
FilerClient filerClient = new FilerClient("localhost", 18888); |
|||
|
|||
List<FilerProto.Entry> entries = filerClient.listEntries("/"); |
|||
|
|||
for (FilerProto.Entry entry : entries) { |
|||
System.out.println(entry.toString()); |
|||
} |
|||
|
|||
filerClient.mkdirs("/new_folder", 0755); |
|||
filerClient.touch("/new_folder/new_empty_file", 0755); |
|||
filerClient.touch("/new_folder/new_empty_file2", 0755); |
|||
filerClient.rm("/new_folder/new_empty_file", false, true); |
|||
filerClient.rm("/new_folder", true, true); |
|||
|
|||
} |
|||
} |
@ -0,0 +1,133 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|||
<parent> |
|||
<artifactId>oss-parent</artifactId> |
|||
<groupId>org.sonatype.oss</groupId> |
|||
<version>9</version> |
|||
<relativePath>../pom.xml/pom.xml</relativePath> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<groupId>com.github.chrislusf</groupId> |
|||
<artifactId>seaweedfs-hadoop2-client</artifactId> |
|||
<version>${seaweedfs.client.version}</version> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<configuration> |
|||
<source>7</source> |
|||
<target>7</target> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-shade-plugin</artifactId> |
|||
<version>3.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>shade</goal> |
|||
</goals> |
|||
<configuration> |
|||
<filters> |
|||
<filter> |
|||
<artifact>*:*</artifact> |
|||
<excludes> |
|||
<exclude>META-INF/*.SF</exclude> |
|||
<exclude>META-INF/*.DSA</exclude> |
|||
<exclude>META-INF/*.RSA</exclude> |
|||
<exclude>org/slf4j/**</exclude> |
|||
<exclude>META-INF/maven/org.slf4j/**</exclude> |
|||
</excludes> |
|||
</filter> |
|||
</filters> |
|||
<transformers> |
|||
<transformer /> |
|||
</transformers> |
|||
<relocations> |
|||
<relocation> |
|||
<pattern>com.google</pattern> |
|||
<shadedPattern>shaded.com.google</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>io.grpc.internal</pattern> |
|||
<shadedPattern>shaded.io.grpc.internal</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.commons</pattern> |
|||
<shadedPattern>shaded.org.apache.commons</shadedPattern> |
|||
<excludes> |
|||
<exclude>org.apache.hadoop</exclude> |
|||
<exclude>org.apache.log4j</exclude> |
|||
</excludes> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.http</pattern> |
|||
<shadedPattern>shaded.org.apache.http</shadedPattern> |
|||
</relocation> |
|||
</relocations> |
|||
</configuration> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-gpg-plugin</artifactId> |
|||
<version>1.5</version> |
|||
<executions> |
|||
<execution> |
|||
<id>sign-artifacts</id> |
|||
<phase>verify</phase> |
|||
<goals> |
|||
<goal>sign</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.sonatype.plugins</groupId> |
|||
<artifactId>nexus-staging-maven-plugin</artifactId> |
|||
<version>1.6.7</version> |
|||
<extensions>true</extensions> |
|||
<configuration> |
|||
<serverId>ossrh</serverId> |
|||
<nexusUrl>https://oss.sonatype.org/</nexusUrl> |
|||
<autoReleaseAfterClose>true</autoReleaseAfterClose> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-source-plugin</artifactId> |
|||
<version>2.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-sources</id> |
|||
<goals> |
|||
<goal>jar-no-fork</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-javadoc-plugin</artifactId> |
|||
<version>2.9.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-javadocs</id> |
|||
<goals> |
|||
<goal>jar</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
<distributionManagement> |
|||
<snapshotRepository> |
|||
<id>ossrh</id> |
|||
<url>https://oss.sonatype.org/content/repositories/snapshots</url> |
|||
</snapshotRepository> |
|||
</distributionManagement> |
|||
<properties> |
|||
<seaweedfs.client.version>1.2.4</seaweedfs.client.version> |
|||
<hadoop.version>2.9.2</hadoop.version> |
|||
</properties> |
|||
</project> |
@ -0,0 +1,163 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<properties> |
|||
<seaweedfs.client.version>1.2.4</seaweedfs.client.version> |
|||
<hadoop.version>2.9.2</hadoop.version> |
|||
</properties> |
|||
|
|||
<groupId>com.github.chrislusf</groupId> |
|||
<artifactId>seaweedfs-hadoop2-client</artifactId> |
|||
<version>${seaweedfs.client.version}</version> |
|||
|
|||
<parent> |
|||
<groupId>org.sonatype.oss</groupId> |
|||
<artifactId>oss-parent</artifactId> |
|||
<version>9</version> |
|||
</parent> |
|||
|
|||
<distributionManagement> |
|||
<snapshotRepository> |
|||
<id>ossrh</id> |
|||
<url>https://oss.sonatype.org/content/repositories/snapshots</url> |
|||
</snapshotRepository> |
|||
</distributionManagement> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<configuration> |
|||
<source>7</source> |
|||
<target>7</target> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-shade-plugin</artifactId> |
|||
<version>3.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>shade</goal> |
|||
</goals> |
|||
<configuration> |
|||
<filters> |
|||
<filter> |
|||
<artifact>*:*</artifact> |
|||
<excludes> |
|||
<exclude>META-INF/*.SF</exclude> |
|||
<exclude>META-INF/*.DSA</exclude> |
|||
<exclude>META-INF/*.RSA</exclude> |
|||
<exclude>org/slf4j/**</exclude> |
|||
<exclude>META-INF/maven/org.slf4j/**</exclude> |
|||
</excludes> |
|||
</filter> |
|||
</filters> |
|||
<transformers> |
|||
<transformer |
|||
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> |
|||
</transformers> |
|||
<relocations> |
|||
<relocation> |
|||
<pattern>com.google</pattern> |
|||
<shadedPattern>shaded.com.google</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>io.grpc.internal</pattern> |
|||
<shadedPattern>shaded.io.grpc.internal</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.commons</pattern> |
|||
<shadedPattern>shaded.org.apache.commons</shadedPattern> |
|||
<excludes> |
|||
<exclude>org.apache.hadoop</exclude> |
|||
<exclude>org.apache.log4j</exclude> |
|||
</excludes> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.http</pattern> |
|||
<shadedPattern>shaded.org.apache.http</shadedPattern> |
|||
</relocation> |
|||
</relocations> |
|||
</configuration> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-gpg-plugin</artifactId> |
|||
<version>1.5</version> |
|||
<executions> |
|||
<execution> |
|||
<id>sign-artifacts</id> |
|||
<phase>verify</phase> |
|||
<goals> |
|||
<goal>sign</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.sonatype.plugins</groupId> |
|||
<artifactId>nexus-staging-maven-plugin</artifactId> |
|||
<version>1.6.7</version> |
|||
<extensions>true</extensions> |
|||
<configuration> |
|||
<serverId>ossrh</serverId> |
|||
<nexusUrl>https://oss.sonatype.org/</nexusUrl> |
|||
<autoReleaseAfterClose>true</autoReleaseAfterClose> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-source-plugin</artifactId> |
|||
<version>2.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-sources</id> |
|||
<goals> |
|||
<goal>jar-no-fork</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-javadoc-plugin</artifactId> |
|||
<version>2.9.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-javadocs</id> |
|||
<goals> |
|||
<goal>jar</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.apache.hadoop</groupId> |
|||
<artifactId>hadoop-client</artifactId> |
|||
<version>${hadoop.version}</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.github.chrislusf</groupId> |
|||
<artifactId>seaweedfs-client</artifactId> |
|||
<version>${seaweedfs.client.version}</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.hadoop</groupId> |
|||
<artifactId>hadoop-common</artifactId> |
|||
<version>${hadoop.version}</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
</project> |
@ -0,0 +1,283 @@ |
|||
package seaweed.hdfs; |
|||
|
|||
// adapted from org.apache.hadoop.fs.azurebfs.services.AbfsOutputStream |
|||
|
|||
import com.google.common.base.Preconditions; |
|||
import org.apache.hadoop.fs.FSExceptionMessages; |
|||
import org.apache.hadoop.fs.Path; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import seaweedfs.client.FilerGrpcClient; |
|||
import seaweedfs.client.FilerProto; |
|||
import seaweedfs.client.SeaweedWrite; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InterruptedIOException; |
|||
import java.io.OutputStream; |
|||
import java.util.concurrent.*; |
|||
|
|||
import static seaweed.hdfs.SeaweedFileSystemStore.getParentDirectory; |
|||
|
|||
public class SeaweedOutputStream extends OutputStream { |
|||
|
|||
private static final Logger LOG = LoggerFactory.getLogger(SeaweedOutputStream.class); |
|||
|
|||
private final FilerGrpcClient filerGrpcClient; |
|||
private final Path path; |
|||
private final int bufferSize; |
|||
private final int maxConcurrentRequestCount; |
|||
private final ThreadPoolExecutor threadExecutor; |
|||
private final ExecutorCompletionService<Void> completionService; |
|||
private FilerProto.Entry.Builder entry; |
|||
private long position; |
|||
private boolean closed; |
|||
private boolean supportFlush = true; |
|||
private volatile IOException lastError; |
|||
private long lastFlushOffset; |
|||
private long lastTotalAppendOffset = 0; |
|||
private byte[] buffer; |
|||
private int bufferIndex; |
|||
private ConcurrentLinkedDeque<WriteOperation> writeOperations; |
|||
private String replication = "000"; |
|||
|
|||
public SeaweedOutputStream(FilerGrpcClient filerGrpcClient, final Path path, FilerProto.Entry.Builder entry, |
|||
final long position, final int bufferSize, final String replication) { |
|||
this.filerGrpcClient = filerGrpcClient; |
|||
this.replication = replication; |
|||
this.path = path; |
|||
this.position = position; |
|||
this.closed = false; |
|||
this.lastError = null; |
|||
this.lastFlushOffset = 0; |
|||
this.bufferSize = bufferSize; |
|||
this.buffer = new byte[bufferSize]; |
|||
this.bufferIndex = 0; |
|||
this.writeOperations = new ConcurrentLinkedDeque<>(); |
|||
|
|||
this.maxConcurrentRequestCount = 4 * Runtime.getRuntime().availableProcessors(); |
|||
|
|||
this.threadExecutor |
|||
= new ThreadPoolExecutor(maxConcurrentRequestCount, |
|||
maxConcurrentRequestCount, |
|||
10L, |
|||
TimeUnit.SECONDS, |
|||
new LinkedBlockingQueue<Runnable>()); |
|||
this.completionService = new ExecutorCompletionService<>(this.threadExecutor); |
|||
|
|||
this.entry = entry; |
|||
|
|||
} |
|||
|
|||
private synchronized void flushWrittenBytesToServiceInternal(final long offset) throws IOException { |
|||
|
|||
LOG.debug("SeaweedWrite.writeMeta path: {} entry:{}", path, entry); |
|||
|
|||
try { |
|||
SeaweedWrite.writeMeta(filerGrpcClient, getParentDirectory(path), entry); |
|||
} catch (Exception ex) { |
|||
throw new IOException(ex); |
|||
} |
|||
this.lastFlushOffset = offset; |
|||
} |
|||
|
|||
@Override |
|||
public void write(final int byteVal) throws IOException { |
|||
write(new byte[]{(byte) (byteVal & 0xFF)}); |
|||
} |
|||
|
|||
@Override |
|||
public synchronized void write(final byte[] data, final int off, final int length) |
|||
throws IOException { |
|||
maybeThrowLastError(); |
|||
|
|||
Preconditions.checkArgument(data != null, "null data"); |
|||
|
|||
if (off < 0 || length < 0 || length > data.length - off) { |
|||
throw new IndexOutOfBoundsException(); |
|||
} |
|||
|
|||
int currentOffset = off; |
|||
int writableBytes = bufferSize - bufferIndex; |
|||
int numberOfBytesToWrite = length; |
|||
|
|||
while (numberOfBytesToWrite > 0) { |
|||
if (writableBytes <= numberOfBytesToWrite) { |
|||
System.arraycopy(data, currentOffset, buffer, bufferIndex, writableBytes); |
|||
bufferIndex += writableBytes; |
|||
writeCurrentBufferToService(); |
|||
currentOffset += writableBytes; |
|||
numberOfBytesToWrite = numberOfBytesToWrite - writableBytes; |
|||
} else { |
|||
System.arraycopy(data, currentOffset, buffer, bufferIndex, numberOfBytesToWrite); |
|||
bufferIndex += numberOfBytesToWrite; |
|||
numberOfBytesToWrite = 0; |
|||
} |
|||
|
|||
writableBytes = bufferSize - bufferIndex; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Flushes this output stream and forces any buffered output bytes to be |
|||
* written out. If any data remains in the payload it is committed to the |
|||
* service. Data is queued for writing and forced out to the service |
|||
* before the call returns. |
|||
*/ |
|||
@Override |
|||
public void flush() throws IOException { |
|||
if (supportFlush) { |
|||
flushInternalAsync(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Force all data in the output stream to be written to Azure storage. |
|||
* Wait to return until this is complete. Close the access to the stream and |
|||
* shutdown the upload thread pool. |
|||
* If the blob was created, its lease will be released. |
|||
* Any error encountered caught in threads and stored will be rethrown here |
|||
* after cleanup. |
|||
*/ |
|||
@Override |
|||
public synchronized void close() throws IOException { |
|||
if (closed) { |
|||
return; |
|||
} |
|||
|
|||
LOG.debug("close path: {}", path); |
|||
try { |
|||
flushInternal(); |
|||
threadExecutor.shutdown(); |
|||
} finally { |
|||
lastError = new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
buffer = null; |
|||
bufferIndex = 0; |
|||
closed = true; |
|||
writeOperations.clear(); |
|||
if (!threadExecutor.isShutdown()) { |
|||
threadExecutor.shutdownNow(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private synchronized void writeCurrentBufferToService() throws IOException { |
|||
if (bufferIndex == 0) { |
|||
return; |
|||
} |
|||
|
|||
final byte[] bytes = buffer; |
|||
final int bytesLength = bufferIndex; |
|||
|
|||
buffer = new byte[bufferSize]; |
|||
bufferIndex = 0; |
|||
final long offset = position; |
|||
position += bytesLength; |
|||
|
|||
if (threadExecutor.getQueue().size() >= maxConcurrentRequestCount * 2) { |
|||
waitForTaskToComplete(); |
|||
} |
|||
|
|||
final Future<Void> job = completionService.submit(new Callable<Void>() { |
|||
@Override |
|||
public Void call() throws Exception { |
|||
// originally: client.append(path, offset, bytes, 0, bytesLength); |
|||
SeaweedWrite.writeData(entry, replication, filerGrpcClient, offset, bytes, 0, bytesLength); |
|||
return null; |
|||
} |
|||
}); |
|||
|
|||
writeOperations.add(new WriteOperation(job, offset, bytesLength)); |
|||
|
|||
// Try to shrink the queue |
|||
shrinkWriteOperationQueue(); |
|||
} |
|||
|
|||
private void waitForTaskToComplete() throws IOException { |
|||
boolean completed; |
|||
for (completed = false; completionService.poll() != null; completed = true) { |
|||
// keep polling until there is no data |
|||
} |
|||
|
|||
if (!completed) { |
|||
try { |
|||
completionService.take(); |
|||
} catch (InterruptedException e) { |
|||
lastError = (IOException) new InterruptedIOException(e.toString()).initCause(e); |
|||
throw lastError; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void maybeThrowLastError() throws IOException { |
|||
if (lastError != null) { |
|||
throw lastError; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Try to remove the completed write operations from the beginning of write |
|||
* operation FIFO queue. |
|||
*/ |
|||
private synchronized void shrinkWriteOperationQueue() throws IOException { |
|||
try { |
|||
while (writeOperations.peek() != null && writeOperations.peek().task.isDone()) { |
|||
writeOperations.peek().task.get(); |
|||
lastTotalAppendOffset += writeOperations.peek().length; |
|||
writeOperations.remove(); |
|||
} |
|||
} catch (Exception e) { |
|||
lastError = new IOException(e); |
|||
throw lastError; |
|||
} |
|||
} |
|||
|
|||
private synchronized void flushInternal() throws IOException { |
|||
maybeThrowLastError(); |
|||
writeCurrentBufferToService(); |
|||
flushWrittenBytesToService(); |
|||
} |
|||
|
|||
private synchronized void flushInternalAsync() throws IOException { |
|||
maybeThrowLastError(); |
|||
writeCurrentBufferToService(); |
|||
flushWrittenBytesToServiceAsync(); |
|||
} |
|||
|
|||
private synchronized void flushWrittenBytesToService() throws IOException { |
|||
for (WriteOperation writeOperation : writeOperations) { |
|||
try { |
|||
writeOperation.task.get(); |
|||
} catch (Exception ex) { |
|||
lastError = new IOException(ex); |
|||
throw lastError; |
|||
} |
|||
} |
|||
LOG.debug("flushWrittenBytesToService: {} position:{}", path, position); |
|||
flushWrittenBytesToServiceInternal(position); |
|||
} |
|||
|
|||
private synchronized void flushWrittenBytesToServiceAsync() throws IOException { |
|||
shrinkWriteOperationQueue(); |
|||
|
|||
if (this.lastTotalAppendOffset > this.lastFlushOffset) { |
|||
this.flushWrittenBytesToServiceInternal(this.lastTotalAppendOffset); |
|||
} |
|||
} |
|||
|
|||
private static class WriteOperation { |
|||
private final Future<Void> task; |
|||
private final long startOffset; |
|||
private final long length; |
|||
|
|||
WriteOperation(final Future<Void> task, final long startOffset, final long length) { |
|||
Preconditions.checkNotNull(task, "task"); |
|||
Preconditions.checkArgument(startOffset >= 0, "startOffset"); |
|||
Preconditions.checkArgument(length >= 0, "length"); |
|||
|
|||
this.task = task; |
|||
this.startOffset = startOffset; |
|||
this.length = length; |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,133 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|||
<parent> |
|||
<artifactId>oss-parent</artifactId> |
|||
<groupId>org.sonatype.oss</groupId> |
|||
<version>9</version> |
|||
<relativePath>../pom.xml/pom.xml</relativePath> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<groupId>com.github.chrislusf</groupId> |
|||
<artifactId>seaweedfs-hadoop3-client</artifactId> |
|||
<version>${seaweedfs.client.version}</version> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<configuration> |
|||
<source>7</source> |
|||
<target>7</target> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-shade-plugin</artifactId> |
|||
<version>3.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>shade</goal> |
|||
</goals> |
|||
<configuration> |
|||
<filters> |
|||
<filter> |
|||
<artifact>*:*</artifact> |
|||
<excludes> |
|||
<exclude>META-INF/*.SF</exclude> |
|||
<exclude>META-INF/*.DSA</exclude> |
|||
<exclude>META-INF/*.RSA</exclude> |
|||
<exclude>org/slf4j/**</exclude> |
|||
<exclude>META-INF/maven/org.slf4j/**</exclude> |
|||
</excludes> |
|||
</filter> |
|||
</filters> |
|||
<transformers> |
|||
<transformer /> |
|||
</transformers> |
|||
<relocations> |
|||
<relocation> |
|||
<pattern>com.google</pattern> |
|||
<shadedPattern>shaded.com.google</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>io.grpc.internal</pattern> |
|||
<shadedPattern>shaded.io.grpc.internal</shadedPattern> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.commons</pattern> |
|||
<shadedPattern>shaded.org.apache.commons</shadedPattern> |
|||
<excludes> |
|||
<exclude>org.apache.hadoop</exclude> |
|||
<exclude>org.apache.log4j</exclude> |
|||
</excludes> |
|||
</relocation> |
|||
<relocation> |
|||
<pattern>org.apache.http</pattern> |
|||
<shadedPattern>shaded.org.apache.http</shadedPattern> |
|||
</relocation> |
|||
</relocations> |
|||
</configuration> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-gpg-plugin</artifactId> |
|||
<version>1.5</version> |
|||
<executions> |
|||
<execution> |
|||
<id>sign-artifacts</id> |
|||
<phase>verify</phase> |
|||
<goals> |
|||
<goal>sign</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.sonatype.plugins</groupId> |
|||
<artifactId>nexus-staging-maven-plugin</artifactId> |
|||
<version>1.6.7</version> |
|||
<extensions>true</extensions> |
|||
<configuration> |
|||
<serverId>ossrh</serverId> |
|||
<nexusUrl>https://oss.sonatype.org/</nexusUrl> |
|||
<autoReleaseAfterClose>true</autoReleaseAfterClose> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-source-plugin</artifactId> |
|||
<version>2.2.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-sources</id> |
|||
<goals> |
|||
<goal>jar-no-fork</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-javadoc-plugin</artifactId> |
|||
<version>2.9.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>attach-javadocs</id> |
|||
<goals> |
|||
<goal>jar</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
<distributionManagement> |
|||
<snapshotRepository> |
|||
<id>ossrh</id> |
|||
<url>https://oss.sonatype.org/content/repositories/snapshots</url> |
|||
</snapshotRepository> |
|||
</distributionManagement> |
|||
<properties> |
|||
<seaweedfs.client.version>1.2.4</seaweedfs.client.version> |
|||
<hadoop.version>3.1.1</hadoop.version> |
|||
</properties> |
|||
</project> |
@ -0,0 +1,137 @@ |
|||
/** |
|||
* Licensed to the Apache Software Foundation (ASF) under one |
|||
* or more contributor license agreements. See the NOTICE file |
|||
* distributed with this work for additional information |
|||
* regarding copyright ownership. The ASF licenses this file |
|||
* to you 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, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
|
|||
package seaweed.hdfs; |
|||
|
|||
import java.util.concurrent.CountDownLatch; |
|||
|
|||
class ReadBuffer { |
|||
|
|||
private SeaweedInputStream stream; |
|||
private long offset; // offset within the file for the buffer |
|||
private int length; // actual length, set after the buffer is filles |
|||
private int requestedLength; // requested length of the read |
|||
private byte[] buffer; // the buffer itself |
|||
private int bufferindex = -1; // index in the buffers array in Buffer manager |
|||
private ReadBufferStatus status; // status of the buffer |
|||
private CountDownLatch latch = null; // signaled when the buffer is done reading, so any client |
|||
// waiting on this buffer gets unblocked |
|||
|
|||
// fields to help with eviction logic |
|||
private long timeStamp = 0; // tick at which buffer became available to read |
|||
private boolean isFirstByteConsumed = false; |
|||
private boolean isLastByteConsumed = false; |
|||
private boolean isAnyByteConsumed = false; |
|||
|
|||
public SeaweedInputStream getStream() { |
|||
return stream; |
|||
} |
|||
|
|||
public void setStream(SeaweedInputStream stream) { |
|||
this.stream = stream; |
|||
} |
|||
|
|||
public long getOffset() { |
|||
return offset; |
|||
} |
|||
|
|||
public void setOffset(long offset) { |
|||
this.offset = offset; |
|||
} |
|||
|
|||
public int getLength() { |
|||
return length; |
|||
} |
|||
|
|||
public void setLength(int length) { |
|||
this.length = length; |
|||
} |
|||
|
|||
public int getRequestedLength() { |
|||
return requestedLength; |
|||
} |
|||
|
|||
public void setRequestedLength(int requestedLength) { |
|||
this.requestedLength = requestedLength; |
|||
} |
|||
|
|||
public byte[] getBuffer() { |
|||
return buffer; |
|||
} |
|||
|
|||
public void setBuffer(byte[] buffer) { |
|||
this.buffer = buffer; |
|||
} |
|||
|
|||
public int getBufferindex() { |
|||
return bufferindex; |
|||
} |
|||
|
|||
public void setBufferindex(int bufferindex) { |
|||
this.bufferindex = bufferindex; |
|||
} |
|||
|
|||
public ReadBufferStatus getStatus() { |
|||
return status; |
|||
} |
|||
|
|||
public void setStatus(ReadBufferStatus status) { |
|||
this.status = status; |
|||
} |
|||
|
|||
public CountDownLatch getLatch() { |
|||
return latch; |
|||
} |
|||
|
|||
public void setLatch(CountDownLatch latch) { |
|||
this.latch = latch; |
|||
} |
|||
|
|||
public long getTimeStamp() { |
|||
return timeStamp; |
|||
} |
|||
|
|||
public void setTimeStamp(long timeStamp) { |
|||
this.timeStamp = timeStamp; |
|||
} |
|||
|
|||
public boolean isFirstByteConsumed() { |
|||
return isFirstByteConsumed; |
|||
} |
|||
|
|||
public void setFirstByteConsumed(boolean isFirstByteConsumed) { |
|||
this.isFirstByteConsumed = isFirstByteConsumed; |
|||
} |
|||
|
|||
public boolean isLastByteConsumed() { |
|||
return isLastByteConsumed; |
|||
} |
|||
|
|||
public void setLastByteConsumed(boolean isLastByteConsumed) { |
|||
this.isLastByteConsumed = isLastByteConsumed; |
|||
} |
|||
|
|||
public boolean isAnyByteConsumed() { |
|||
return isAnyByteConsumed; |
|||
} |
|||
|
|||
public void setAnyByteConsumed(boolean isAnyByteConsumed) { |
|||
this.isAnyByteConsumed = isAnyByteConsumed; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,394 @@ |
|||
/** |
|||
* Licensed to the Apache Software Foundation (ASF) under one |
|||
* or more contributor license agreements. See the NOTICE file |
|||
* distributed with this work for additional information |
|||
* regarding copyright ownership. The ASF licenses this file |
|||
* to you 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 |
|||
* <p> |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* <p> |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package seaweed.hdfs; |
|||
|
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.LinkedList; |
|||
import java.util.Queue; |
|||
import java.util.Stack; |
|||
import java.util.concurrent.CountDownLatch; |
|||
|
|||
/** |
|||
* The Read Buffer Manager for Rest AbfsClient. |
|||
*/ |
|||
final class ReadBufferManager { |
|||
private static final Logger LOGGER = LoggerFactory.getLogger(ReadBufferManager.class); |
|||
|
|||
private static final int NUM_BUFFERS = 16; |
|||
private static final int BLOCK_SIZE = 4 * 1024 * 1024; |
|||
private static final int NUM_THREADS = 8; |
|||
private static final int THRESHOLD_AGE_MILLISECONDS = 3000; // have to see if 3 seconds is a good threshold |
|||
|
|||
private Thread[] threads = new Thread[NUM_THREADS]; |
|||
private byte[][] buffers; // array of byte[] buffers, to hold the data that is read |
|||
private Stack<Integer> freeList = new Stack<>(); // indices in buffers[] array that are available |
|||
|
|||
private Queue<ReadBuffer> readAheadQueue = new LinkedList<>(); // queue of requests that are not picked up by any worker thread yet |
|||
private LinkedList<ReadBuffer> inProgressList = new LinkedList<>(); // requests being processed by worker threads |
|||
private LinkedList<ReadBuffer> completedReadList = new LinkedList<>(); // buffers available for reading |
|||
private static final ReadBufferManager BUFFER_MANAGER; // singleton, initialized in static initialization block |
|||
|
|||
static { |
|||
BUFFER_MANAGER = new ReadBufferManager(); |
|||
BUFFER_MANAGER.init(); |
|||
} |
|||
|
|||
static ReadBufferManager getBufferManager() { |
|||
return BUFFER_MANAGER; |
|||
} |
|||
|
|||
private void init() { |
|||
buffers = new byte[NUM_BUFFERS][]; |
|||
for (int i = 0; i < NUM_BUFFERS; i++) { |
|||
buffers[i] = new byte[BLOCK_SIZE]; // same buffers are reused. The byte array never goes back to GC |
|||
freeList.add(i); |
|||
} |
|||
for (int i = 0; i < NUM_THREADS; i++) { |
|||
Thread t = new Thread(new ReadBufferWorker(i)); |
|||
t.setDaemon(true); |
|||
threads[i] = t; |
|||
t.setName("SeaweedFS-prefetch-" + i); |
|||
t.start(); |
|||
} |
|||
ReadBufferWorker.UNLEASH_WORKERS.countDown(); |
|||
} |
|||
|
|||
// hide instance constructor |
|||
private ReadBufferManager() { |
|||
} |
|||
|
|||
|
|||
/* |
|||
* |
|||
* SeaweedInputStream-facing methods |
|||
* |
|||
*/ |
|||
|
|||
|
|||
/** |
|||
* {@link SeaweedInputStream} calls this method to queue read-aheads. |
|||
* |
|||
* @param stream The {@link SeaweedInputStream} for which to do the read-ahead |
|||
* @param requestedOffset The offset in the file which shoukd be read |
|||
* @param requestedLength The length to read |
|||
*/ |
|||
void queueReadAhead(final SeaweedInputStream stream, final long requestedOffset, final int requestedLength) { |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("Start Queueing readAhead for {} offset {} length {}", |
|||
stream.getPath(), requestedOffset, requestedLength); |
|||
} |
|||
ReadBuffer buffer; |
|||
synchronized (this) { |
|||
if (isAlreadyQueued(stream, requestedOffset)) { |
|||
return; // already queued, do not queue again |
|||
} |
|||
if (freeList.isEmpty() && !tryEvict()) { |
|||
return; // no buffers available, cannot queue anything |
|||
} |
|||
|
|||
buffer = new ReadBuffer(); |
|||
buffer.setStream(stream); |
|||
buffer.setOffset(requestedOffset); |
|||
buffer.setLength(0); |
|||
buffer.setRequestedLength(requestedLength); |
|||
buffer.setStatus(ReadBufferStatus.NOT_AVAILABLE); |
|||
buffer.setLatch(new CountDownLatch(1)); |
|||
|
|||
Integer bufferIndex = freeList.pop(); // will return a value, since we have checked size > 0 already |
|||
|
|||
buffer.setBuffer(buffers[bufferIndex]); |
|||
buffer.setBufferindex(bufferIndex); |
|||
readAheadQueue.add(buffer); |
|||
notifyAll(); |
|||
} |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("Done q-ing readAhead for file {} offset {} buffer idx {}", |
|||
stream.getPath(), requestedOffset, buffer.getBufferindex()); |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* {@link SeaweedInputStream} calls this method read any bytes already available in a buffer (thereby saving a |
|||
* remote read). This returns the bytes if the data already exists in buffer. If there is a buffer that is reading |
|||
* the requested offset, then this method blocks until that read completes. If the data is queued in a read-ahead |
|||
* but not picked up by a worker thread yet, then it cancels that read-ahead and reports cache miss. This is because |
|||
* depending on worker thread availability, the read-ahead may take a while - the calling thread can do it's own |
|||
* read to get the data faster (copmared to the read waiting in queue for an indeterminate amount of time). |
|||
* |
|||
* @param stream the file to read bytes for |
|||
* @param position the offset in the file to do a read for |
|||
* @param length the length to read |
|||
* @param buffer the buffer to read data into. Note that the buffer will be written into from offset 0. |
|||
* @return the number of bytes read |
|||
*/ |
|||
int getBlock(final SeaweedInputStream stream, final long position, final int length, final byte[] buffer) { |
|||
// not synchronized, so have to be careful with locking |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("getBlock for file {} position {} thread {}", |
|||
stream.getPath(), position, Thread.currentThread().getName()); |
|||
} |
|||
|
|||
waitForProcess(stream, position); |
|||
|
|||
int bytesRead = 0; |
|||
synchronized (this) { |
|||
bytesRead = getBlockFromCompletedQueue(stream, position, length, buffer); |
|||
} |
|||
if (bytesRead > 0) { |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("Done read from Cache for {} position {} length {}", |
|||
stream.getPath(), position, bytesRead); |
|||
} |
|||
return bytesRead; |
|||
} |
|||
|
|||
// otherwise, just say we got nothing - calling thread can do its own read |
|||
return 0; |
|||
} |
|||
|
|||
/* |
|||
* |
|||
* Internal methods |
|||
* |
|||
*/ |
|||
|
|||
private void waitForProcess(final SeaweedInputStream stream, final long position) { |
|||
ReadBuffer readBuf; |
|||
synchronized (this) { |
|||
clearFromReadAheadQueue(stream, position); |
|||
readBuf = getFromList(inProgressList, stream, position); |
|||
} |
|||
if (readBuf != null) { // if in in-progress queue, then block for it |
|||
try { |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("got a relevant read buffer for file {} offset {} buffer idx {}", |
|||
stream.getPath(), readBuf.getOffset(), readBuf.getBufferindex()); |
|||
} |
|||
readBuf.getLatch().await(); // blocking wait on the caller stream's thread |
|||
// Note on correctness: readBuf gets out of inProgressList only in 1 place: after worker thread |
|||
// is done processing it (in doneReading). There, the latch is set after removing the buffer from |
|||
// inProgressList. So this latch is safe to be outside the synchronized block. |
|||
// Putting it in synchronized would result in a deadlock, since this thread would be holding the lock |
|||
// while waiting, so no one will be able to change any state. If this becomes more complex in the future, |
|||
// then the latch cane be removed and replaced with wait/notify whenever inProgressList is touched. |
|||
} catch (InterruptedException ex) { |
|||
Thread.currentThread().interrupt(); |
|||
} |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("latch done for file {} buffer idx {} length {}", |
|||
stream.getPath(), readBuf.getBufferindex(), readBuf.getLength()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* If any buffer in the completedlist can be reclaimed then reclaim it and return the buffer to free list. |
|||
* The objective is to find just one buffer - there is no advantage to evicting more than one. |
|||
* |
|||
* @return whether the eviction succeeeded - i.e., were we able to free up one buffer |
|||
*/ |
|||
private synchronized boolean tryEvict() { |
|||
ReadBuffer nodeToEvict = null; |
|||
if (completedReadList.size() <= 0) { |
|||
return false; // there are no evict-able buffers |
|||
} |
|||
|
|||
// first, try buffers where all bytes have been consumed (approximated as first and last bytes consumed) |
|||
for (ReadBuffer buf : completedReadList) { |
|||
if (buf.isFirstByteConsumed() && buf.isLastByteConsumed()) { |
|||
nodeToEvict = buf; |
|||
break; |
|||
} |
|||
} |
|||
if (nodeToEvict != null) { |
|||
return evict(nodeToEvict); |
|||
} |
|||
|
|||
// next, try buffers where any bytes have been consumed (may be a bad idea? have to experiment and see) |
|||
for (ReadBuffer buf : completedReadList) { |
|||
if (buf.isAnyByteConsumed()) { |
|||
nodeToEvict = buf; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (nodeToEvict != null) { |
|||
return evict(nodeToEvict); |
|||
} |
|||
|
|||
// next, try any old nodes that have not been consumed |
|||
long earliestBirthday = Long.MAX_VALUE; |
|||
for (ReadBuffer buf : completedReadList) { |
|||
if (buf.getTimeStamp() < earliestBirthday) { |
|||
nodeToEvict = buf; |
|||
earliestBirthday = buf.getTimeStamp(); |
|||
} |
|||
} |
|||
if ((currentTimeMillis() - earliestBirthday > THRESHOLD_AGE_MILLISECONDS) && (nodeToEvict != null)) { |
|||
return evict(nodeToEvict); |
|||
} |
|||
|
|||
// nothing can be evicted |
|||
return false; |
|||
} |
|||
|
|||
private boolean evict(final ReadBuffer buf) { |
|||
freeList.push(buf.getBufferindex()); |
|||
completedReadList.remove(buf); |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("Evicting buffer idx {}; was used for file {} offset {} length {}", |
|||
buf.getBufferindex(), buf.getStream().getPath(), buf.getOffset(), buf.getLength()); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
private boolean isAlreadyQueued(final SeaweedInputStream stream, final long requestedOffset) { |
|||
// returns true if any part of the buffer is already queued |
|||
return (isInList(readAheadQueue, stream, requestedOffset) |
|||
|| isInList(inProgressList, stream, requestedOffset) |
|||
|| isInList(completedReadList, stream, requestedOffset)); |
|||
} |
|||
|
|||
private boolean isInList(final Collection<ReadBuffer> list, final SeaweedInputStream stream, final long requestedOffset) { |
|||
return (getFromList(list, stream, requestedOffset) != null); |
|||
} |
|||
|
|||
private ReadBuffer getFromList(final Collection<ReadBuffer> list, final SeaweedInputStream stream, final long requestedOffset) { |
|||
for (ReadBuffer buffer : list) { |
|||
if (buffer.getStream() == stream) { |
|||
if (buffer.getStatus() == ReadBufferStatus.AVAILABLE |
|||
&& requestedOffset >= buffer.getOffset() |
|||
&& requestedOffset < buffer.getOffset() + buffer.getLength()) { |
|||
return buffer; |
|||
} else if (requestedOffset >= buffer.getOffset() |
|||
&& requestedOffset < buffer.getOffset() + buffer.getRequestedLength()) { |
|||
return buffer; |
|||
} |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private void clearFromReadAheadQueue(final SeaweedInputStream stream, final long requestedOffset) { |
|||
ReadBuffer buffer = getFromList(readAheadQueue, stream, requestedOffset); |
|||
if (buffer != null) { |
|||
readAheadQueue.remove(buffer); |
|||
notifyAll(); // lock is held in calling method |
|||
freeList.push(buffer.getBufferindex()); |
|||
} |
|||
} |
|||
|
|||
private int getBlockFromCompletedQueue(final SeaweedInputStream stream, final long position, final int length, |
|||
final byte[] buffer) { |
|||
ReadBuffer buf = getFromList(completedReadList, stream, position); |
|||
if (buf == null || position >= buf.getOffset() + buf.getLength()) { |
|||
return 0; |
|||
} |
|||
int cursor = (int) (position - buf.getOffset()); |
|||
int availableLengthInBuffer = buf.getLength() - cursor; |
|||
int lengthToCopy = Math.min(length, availableLengthInBuffer); |
|||
System.arraycopy(buf.getBuffer(), cursor, buffer, 0, lengthToCopy); |
|||
if (cursor == 0) { |
|||
buf.setFirstByteConsumed(true); |
|||
} |
|||
if (cursor + lengthToCopy == buf.getLength()) { |
|||
buf.setLastByteConsumed(true); |
|||
} |
|||
buf.setAnyByteConsumed(true); |
|||
return lengthToCopy; |
|||
} |
|||
|
|||
/* |
|||
* |
|||
* ReadBufferWorker-thread-facing methods |
|||
* |
|||
*/ |
|||
|
|||
/** |
|||
* ReadBufferWorker thread calls this to get the next buffer that it should work on. |
|||
* |
|||
* @return {@link ReadBuffer} |
|||
* @throws InterruptedException if thread is interrupted |
|||
*/ |
|||
ReadBuffer getNextBlockToRead() throws InterruptedException { |
|||
ReadBuffer buffer = null; |
|||
synchronized (this) { |
|||
//buffer = readAheadQueue.take(); // blocking method |
|||
while (readAheadQueue.size() == 0) { |
|||
wait(); |
|||
} |
|||
buffer = readAheadQueue.remove(); |
|||
notifyAll(); |
|||
if (buffer == null) { |
|||
return null; // should never happen |
|||
} |
|||
buffer.setStatus(ReadBufferStatus.READING_IN_PROGRESS); |
|||
inProgressList.add(buffer); |
|||
} |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("ReadBufferWorker picked file {} for offset {}", |
|||
buffer.getStream().getPath(), buffer.getOffset()); |
|||
} |
|||
return buffer; |
|||
} |
|||
|
|||
/** |
|||
* ReadBufferWorker thread calls this method to post completion. |
|||
* |
|||
* @param buffer the buffer whose read was completed |
|||
* @param result the {@link ReadBufferStatus} after the read operation in the worker thread |
|||
* @param bytesActuallyRead the number of bytes that the worker thread was actually able to read |
|||
*/ |
|||
void doneReading(final ReadBuffer buffer, final ReadBufferStatus result, final int bytesActuallyRead) { |
|||
if (LOGGER.isTraceEnabled()) { |
|||
LOGGER.trace("ReadBufferWorker completed file {} for offset {} bytes {}", |
|||
buffer.getStream().getPath(), buffer.getOffset(), bytesActuallyRead); |
|||
} |
|||
synchronized (this) { |
|||
inProgressList.remove(buffer); |
|||
if (result == ReadBufferStatus.AVAILABLE && bytesActuallyRead > 0) { |
|||
buffer.setStatus(ReadBufferStatus.AVAILABLE); |
|||
buffer.setTimeStamp(currentTimeMillis()); |
|||
buffer.setLength(bytesActuallyRead); |
|||
completedReadList.add(buffer); |
|||
} else { |
|||
freeList.push(buffer.getBufferindex()); |
|||
// buffer should go out of scope after the end of the calling method in ReadBufferWorker, and eligible for GC |
|||
} |
|||
} |
|||
//outside the synchronized, since anyone receiving a wake-up from the latch must see safe-published results |
|||
buffer.getLatch().countDown(); // wake up waiting threads (if any) |
|||
} |
|||
|
|||
/** |
|||
* Similar to System.currentTimeMillis, except implemented with System.nanoTime(). |
|||
* System.currentTimeMillis can go backwards when system clock is changed (e.g., with NTP time synchronization), |
|||
* making it unsuitable for measuring time intervals. nanotime is strictly monotonically increasing per CPU core. |
|||
* Note: it is not monotonic across Sockets, and even within a CPU, its only the |
|||
* more recent parts which share a clock across all cores. |
|||
* |
|||
* @return current time in milliseconds |
|||
*/ |
|||
private long currentTimeMillis() { |
|||
return System.nanoTime() / 1000 / 1000; |
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Licensed to the Apache Software Foundation (ASF) under one |
|||
* or more contributor license agreements. See the NOTICE file |
|||
* distributed with this work for additional information |
|||
* regarding copyright ownership. The ASF licenses this file |
|||
* to you 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, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
|
|||
package seaweed.hdfs; |
|||
|
|||
/** |
|||
* The ReadBufferStatus for Rest AbfsClient |
|||
*/ |
|||
public enum ReadBufferStatus { |
|||
NOT_AVAILABLE, // buffers sitting in readaheadqueue have this stats |
|||
READING_IN_PROGRESS, // reading is in progress on this buffer. Buffer should be in inProgressList |
|||
AVAILABLE, // data is available in buffer. It should be in completedList |
|||
READ_FAILED // read completed, but failed. |
|||
} |
@ -0,0 +1,70 @@ |
|||
/** |
|||
* Licensed to the Apache Software Foundation (ASF) under one |
|||
* or more contributor license agreements. See the NOTICE file |
|||
* distributed with this work for additional information |
|||
* regarding copyright ownership. The ASF licenses this file |
|||
* to you 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, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
|
|||
package seaweed.hdfs; |
|||
|
|||
import java.util.concurrent.CountDownLatch; |
|||
|
|||
class ReadBufferWorker implements Runnable { |
|||
|
|||
protected static final CountDownLatch UNLEASH_WORKERS = new CountDownLatch(1); |
|||
private int id; |
|||
|
|||
ReadBufferWorker(final int id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
/** |
|||
* return the ID of ReadBufferWorker. |
|||
*/ |
|||
public int getId() { |
|||
return this.id; |
|||
} |
|||
|
|||
/** |
|||
* Waits until a buffer becomes available in ReadAheadQueue. |
|||
* Once a buffer becomes available, reads the file specified in it and then posts results back to buffer manager. |
|||
* Rinse and repeat. Forever. |
|||
*/ |
|||
public void run() { |
|||
try { |
|||
UNLEASH_WORKERS.await(); |
|||
} catch (InterruptedException ex) { |
|||
Thread.currentThread().interrupt(); |
|||
} |
|||
ReadBufferManager bufferManager = ReadBufferManager.getBufferManager(); |
|||
ReadBuffer buffer; |
|||
while (true) { |
|||
try { |
|||
buffer = bufferManager.getNextBlockToRead(); // blocks, until a buffer is available for this thread |
|||
} catch (InterruptedException ex) { |
|||
Thread.currentThread().interrupt(); |
|||
return; |
|||
} |
|||
if (buffer != null) { |
|||
try { |
|||
// do the actual read, from the file. |
|||
int bytesRead = buffer.getStream().readRemote(buffer.getOffset(), buffer.getBuffer(), 0, buffer.getRequestedLength()); |
|||
bufferManager.doneReading(buffer, ReadBufferStatus.AVAILABLE, bytesRead); // post result back to ReadBufferManager |
|||
} catch (Exception ex) { |
|||
bufferManager.doneReading(buffer, ReadBufferStatus.READ_FAILED, 0); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,620 @@ |
|||
package seaweed.hdfs; |
|||
|
|||
import org.apache.hadoop.conf.Configuration; |
|||
import org.apache.hadoop.fs.*; |
|||
import org.apache.hadoop.fs.permission.AclEntry; |
|||
import org.apache.hadoop.fs.permission.AclStatus; |
|||
import org.apache.hadoop.fs.permission.FsPermission; |
|||
import org.apache.hadoop.security.AccessControlException; |
|||
import org.apache.hadoop.security.UserGroupInformation; |
|||
import org.apache.hadoop.util.Progressable; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.io.FileNotFoundException; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
import java.net.URI; |
|||
import java.util.EnumSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_KEY; |
|||
|
|||
public class SeaweedFileSystem extends FileSystem { |
|||
|
|||
public static final int FS_SEAWEED_DEFAULT_PORT = 8888; |
|||
public static final String FS_SEAWEED_FILER_HOST = "fs.seaweed.filer.host"; |
|||
public static final String FS_SEAWEED_FILER_PORT = "fs.seaweed.filer.port"; |
|||
|
|||
private static final Logger LOG = LoggerFactory.getLogger(SeaweedFileSystem.class); |
|||
private static int BUFFER_SIZE = 16 * 1024 * 1024; |
|||
|
|||
private URI uri; |
|||
private Path workingDirectory = new Path("/"); |
|||
private SeaweedFileSystemStore seaweedFileSystemStore; |
|||
|
|||
public URI getUri() { |
|||
return uri; |
|||
} |
|||
|
|||
public String getScheme() { |
|||
return "seaweedfs"; |
|||
} |
|||
|
|||
@Override |
|||
public void initialize(URI uri, Configuration conf) throws IOException { // get |
|||
super.initialize(uri, conf); |
|||
|
|||
// get host information from uri (overrides info in conf) |
|||
String host = uri.getHost(); |
|||
host = (host == null) ? conf.get(FS_SEAWEED_FILER_HOST, "localhost") : host; |
|||
if (host == null) { |
|||
throw new IOException("Invalid host specified"); |
|||
} |
|||
conf.set(FS_SEAWEED_FILER_HOST, host); |
|||
|
|||
// get port information from uri, (overrides info in conf) |
|||
int port = uri.getPort(); |
|||
port = (port == -1) ? FS_SEAWEED_DEFAULT_PORT : port; |
|||
conf.setInt(FS_SEAWEED_FILER_PORT, port); |
|||
|
|||
conf.setInt(IO_FILE_BUFFER_SIZE_KEY, BUFFER_SIZE); |
|||
|
|||
setConf(conf); |
|||
this.uri = uri; |
|||
|
|||
seaweedFileSystemStore = new SeaweedFileSystemStore(host, port); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public FSDataInputStream open(Path path, int bufferSize) throws IOException { |
|||
|
|||
LOG.debug("open path: {} bufferSize:{}", path, bufferSize); |
|||
|
|||
path = qualify(path); |
|||
|
|||
try { |
|||
InputStream inputStream = seaweedFileSystemStore.openFileForRead(path, statistics, bufferSize); |
|||
return new FSDataInputStream(inputStream); |
|||
} catch (Exception ex) { |
|||
LOG.warn("open path: {} bufferSize:{}", path, bufferSize, ex); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public FSDataOutputStream create(Path path, FsPermission permission, final boolean overwrite, final int bufferSize, |
|||
final short replication, final long blockSize, final Progressable progress) throws IOException { |
|||
|
|||
LOG.debug("create path: {} bufferSize:{} blockSize:{}", path, bufferSize, blockSize); |
|||
|
|||
path = qualify(path); |
|||
|
|||
try { |
|||
String replicaPlacement = String.format("%03d", replication - 1); |
|||
OutputStream outputStream = seaweedFileSystemStore.createFile(path, overwrite, permission, bufferSize, replicaPlacement); |
|||
return new FSDataOutputStream(outputStream, statistics); |
|||
} catch (Exception ex) { |
|||
LOG.warn("create path: {} bufferSize:{} blockSize:{}", path, bufferSize, blockSize, ex); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* {@inheritDoc} |
|||
* @throws FileNotFoundException if the parent directory is not present -or |
|||
* is not a directory. |
|||
*/ |
|||
@Override |
|||
public FSDataOutputStream createNonRecursive(Path path, |
|||
FsPermission permission, |
|||
EnumSet<CreateFlag> flags, |
|||
int bufferSize, |
|||
short replication, |
|||
long blockSize, |
|||
Progressable progress) throws IOException { |
|||
Path parent = path.getParent(); |
|||
if (parent != null) { |
|||
// expect this to raise an exception if there is no parent |
|||
if (!getFileStatus(parent).isDirectory()) { |
|||
throw new FileAlreadyExistsException("Not a directory: " + parent); |
|||
} |
|||
} |
|||
return create(path, permission, |
|||
flags.contains(CreateFlag.OVERWRITE), bufferSize, |
|||
replication, blockSize, progress); |
|||
} |
|||
|
|||
@Override |
|||
public FSDataOutputStream append(Path path, int bufferSize, Progressable progressable) throws IOException { |
|||
|
|||
LOG.debug("append path: {} bufferSize:{}", path, bufferSize); |
|||
|
|||
path = qualify(path); |
|||
try { |
|||
OutputStream outputStream = seaweedFileSystemStore.createFile(path, false, null, bufferSize, ""); |
|||
return new FSDataOutputStream(outputStream, statistics); |
|||
} catch (Exception ex) { |
|||
LOG.warn("append path: {} bufferSize:{}", path, bufferSize, ex); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public boolean rename(Path src, Path dst) { |
|||
|
|||
LOG.debug("rename path: {} => {}", src, dst); |
|||
|
|||
if (src.isRoot()) { |
|||
return false; |
|||
} |
|||
|
|||
if (src.equals(dst)) { |
|||
return true; |
|||
} |
|||
FileStatus dstFileStatus = getFileStatus(dst); |
|||
|
|||
String sourceFileName = src.getName(); |
|||
Path adjustedDst = dst; |
|||
|
|||
if (dstFileStatus != null) { |
|||
if (!dstFileStatus.isDirectory()) { |
|||
return false; |
|||
} |
|||
adjustedDst = new Path(dst, sourceFileName); |
|||
} |
|||
|
|||
Path qualifiedSrcPath = qualify(src); |
|||
Path qualifiedDstPath = qualify(adjustedDst); |
|||
|
|||
seaweedFileSystemStore.rename(qualifiedSrcPath, qualifiedDstPath); |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public boolean delete(Path path, boolean recursive) { |
|||
|
|||
LOG.debug("delete path: {} recursive:{}", path, recursive); |
|||
|
|||
path = qualify(path); |
|||
|
|||
FileStatus fileStatus = getFileStatus(path); |
|||
|
|||
if (fileStatus == null) { |
|||
return true; |
|||
} |
|||
|
|||
return seaweedFileSystemStore.deleteEntries(path, fileStatus.isDirectory(), recursive); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public FileStatus[] listStatus(Path path) throws IOException { |
|||
|
|||
LOG.debug("listStatus path: {}", path); |
|||
|
|||
path = qualify(path); |
|||
|
|||
return seaweedFileSystemStore.listEntries(path); |
|||
} |
|||
|
|||
@Override |
|||
public Path getWorkingDirectory() { |
|||
return workingDirectory; |
|||
} |
|||
|
|||
@Override |
|||
public void setWorkingDirectory(Path path) { |
|||
if (path.isAbsolute()) { |
|||
workingDirectory = path; |
|||
} else { |
|||
workingDirectory = new Path(workingDirectory, path); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public boolean mkdirs(Path path, FsPermission fsPermission) throws IOException { |
|||
|
|||
LOG.debug("mkdirs path: {}", path); |
|||
|
|||
path = qualify(path); |
|||
|
|||
FileStatus fileStatus = getFileStatus(path); |
|||
|
|||
if (fileStatus == null) { |
|||
|
|||
UserGroupInformation currentUser = UserGroupInformation.getCurrentUser(); |
|||
return seaweedFileSystemStore.createDirectory(path, currentUser, |
|||
fsPermission == null ? FsPermission.getDirDefault() : fsPermission, |
|||
FsPermission.getUMask(getConf())); |
|||
|
|||
} |
|||
|
|||
if (fileStatus.isDirectory()) { |
|||
return true; |
|||
} else { |
|||
throw new FileAlreadyExistsException("Path is a file: " + path); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public FileStatus getFileStatus(Path path) { |
|||
|
|||
LOG.debug("getFileStatus path: {}", path); |
|||
|
|||
path = qualify(path); |
|||
|
|||
return seaweedFileSystemStore.getFileStatus(path); |
|||
} |
|||
|
|||
/** |
|||
* Set owner of a path (i.e. a file or a directory). |
|||
* The parameters owner and group cannot both be null. |
|||
* |
|||
* @param path The path |
|||
* @param owner If it is null, the original username remains unchanged. |
|||
* @param group If it is null, the original groupname remains unchanged. |
|||
*/ |
|||
@Override |
|||
public void setOwner(Path path, final String owner, final String group) |
|||
throws IOException { |
|||
LOG.debug("setOwner path: {}", path); |
|||
path = qualify(path); |
|||
|
|||
seaweedFileSystemStore.setOwner(path, owner, group); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Set permission of a path. |
|||
* |
|||
* @param path The path |
|||
* @param permission Access permission |
|||
*/ |
|||
@Override |
|||
public void setPermission(Path path, final FsPermission permission) throws IOException { |
|||
LOG.debug("setPermission path: {}", path); |
|||
|
|||
if (permission == null) { |
|||
throw new IllegalArgumentException("The permission can't be null"); |
|||
} |
|||
|
|||
path = qualify(path); |
|||
|
|||
seaweedFileSystemStore.setPermission(path, permission); |
|||
} |
|||
|
|||
Path qualify(Path path) { |
|||
return path.makeQualified(uri, workingDirectory); |
|||
} |
|||
|
|||
/** |
|||
* Concat existing files together. |
|||
* |
|||
* @param trg the path to the target destination. |
|||
* @param psrcs the paths to the sources to use for the concatenation. |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default). |
|||
*/ |
|||
@Override |
|||
public void concat(final Path trg, final Path[] psrcs) throws IOException { |
|||
throw new UnsupportedOperationException("Not implemented by the " + |
|||
getClass().getSimpleName() + " FileSystem implementation"); |
|||
} |
|||
|
|||
/** |
|||
* Truncate the file in the indicated path to the indicated size. |
|||
* <ul> |
|||
* <li>Fails if path is a directory.</li> |
|||
* <li>Fails if path does not exist.</li> |
|||
* <li>Fails if path is not closed.</li> |
|||
* <li>Fails if new size is greater than current size.</li> |
|||
* </ul> |
|||
* |
|||
* @param f The path to the file to be truncated |
|||
* @param newLength The size the file is to be truncated to |
|||
* @return <code>true</code> if the file has been truncated to the desired |
|||
* <code>newLength</code> and is immediately available to be reused for |
|||
* write operations such as <code>append</code>, or |
|||
* <code>false</code> if a background process of adjusting the length of |
|||
* the last block has been started, and clients should wait for it to |
|||
* complete before proceeding with further file updates. |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default). |
|||
*/ |
|||
@Override |
|||
public boolean truncate(Path f, long newLength) throws IOException { |
|||
throw new UnsupportedOperationException("Not implemented by the " + |
|||
getClass().getSimpleName() + " FileSystem implementation"); |
|||
} |
|||
|
|||
@Override |
|||
public void createSymlink(final Path target, final Path link, |
|||
final boolean createParent) throws AccessControlException, |
|||
FileAlreadyExistsException, FileNotFoundException, |
|||
ParentNotDirectoryException, UnsupportedFileSystemException, |
|||
IOException { |
|||
// Supporting filesystems should override this method |
|||
throw new UnsupportedOperationException( |
|||
"Filesystem does not support symlinks!"); |
|||
} |
|||
|
|||
public boolean supportsSymlinks() { |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Create a snapshot. |
|||
* |
|||
* @param path The directory where snapshots will be taken. |
|||
* @param snapshotName The name of the snapshot |
|||
* @return the snapshot path. |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
*/ |
|||
@Override |
|||
public Path createSnapshot(Path path, String snapshotName) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support createSnapshot"); |
|||
} |
|||
|
|||
/** |
|||
* Rename a snapshot. |
|||
* |
|||
* @param path The directory path where the snapshot was taken |
|||
* @param snapshotOldName Old name of the snapshot |
|||
* @param snapshotNewName New name of the snapshot |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void renameSnapshot(Path path, String snapshotOldName, |
|||
String snapshotNewName) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support renameSnapshot"); |
|||
} |
|||
|
|||
/** |
|||
* Delete a snapshot of a directory. |
|||
* |
|||
* @param path The directory that the to-be-deleted snapshot belongs to |
|||
* @param snapshotName The name of the snapshot |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void deleteSnapshot(Path path, String snapshotName) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support deleteSnapshot"); |
|||
} |
|||
|
|||
/** |
|||
* Modifies ACL entries of files and directories. This method can add new ACL |
|||
* entries or modify the permissions on existing ACL entries. All existing |
|||
* ACL entries that are not specified in this call are retained without |
|||
* changes. (Modifications are merged into the current ACL.) |
|||
* |
|||
* @param path Path to modify |
|||
* @param aclSpec List<AclEntry> describing modifications |
|||
* @throws IOException if an ACL could not be modified |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void modifyAclEntries(Path path, List<AclEntry> aclSpec) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support modifyAclEntries"); |
|||
} |
|||
|
|||
/** |
|||
* Removes ACL entries from files and directories. Other ACL entries are |
|||
* retained. |
|||
* |
|||
* @param path Path to modify |
|||
* @param aclSpec List describing entries to remove |
|||
* @throws IOException if an ACL could not be modified |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void removeAclEntries(Path path, List<AclEntry> aclSpec) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support removeAclEntries"); |
|||
} |
|||
|
|||
/** |
|||
* Removes all default ACL entries from files and directories. |
|||
* |
|||
* @param path Path to modify |
|||
* @throws IOException if an ACL could not be modified |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void removeDefaultAcl(Path path) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support removeDefaultAcl"); |
|||
} |
|||
|
|||
/** |
|||
* Removes all but the base ACL entries of files and directories. The entries |
|||
* for user, group, and others are retained for compatibility with permission |
|||
* bits. |
|||
* |
|||
* @param path Path to modify |
|||
* @throws IOException if an ACL could not be removed |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void removeAcl(Path path) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support removeAcl"); |
|||
} |
|||
|
|||
/** |
|||
* Fully replaces ACL of files and directories, discarding all existing |
|||
* entries. |
|||
* |
|||
* @param path Path to modify |
|||
* @param aclSpec List describing modifications, which must include entries |
|||
* for user, group, and others for compatibility with permission bits. |
|||
* @throws IOException if an ACL could not be modified |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support setAcl"); |
|||
} |
|||
|
|||
/** |
|||
* Gets the ACL of a file or directory. |
|||
* |
|||
* @param path Path to get |
|||
* @return AclStatus describing the ACL of the file or directory |
|||
* @throws IOException if an ACL could not be read |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public AclStatus getAclStatus(Path path) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support getAclStatus"); |
|||
} |
|||
|
|||
/** |
|||
* Set an xattr of a file or directory. |
|||
* The name must be prefixed with the namespace followed by ".". For example, |
|||
* "user.attr". |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to modify |
|||
* @param name xattr name. |
|||
* @param value xattr value. |
|||
* @param flag xattr set flag |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void setXAttr(Path path, String name, byte[] value, |
|||
EnumSet<XAttrSetFlag> flag) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support setXAttr"); |
|||
} |
|||
|
|||
/** |
|||
* Get an xattr name and value for a file or directory. |
|||
* The name must be prefixed with the namespace followed by ".". For example, |
|||
* "user.attr". |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to get extended attribute |
|||
* @param name xattr name. |
|||
* @return byte[] xattr value. |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public byte[] getXAttr(Path path, String name) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support getXAttr"); |
|||
} |
|||
|
|||
/** |
|||
* Get all of the xattr name/value pairs for a file or directory. |
|||
* Only those xattrs which the logged-in user has permissions to view |
|||
* are returned. |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to get extended attributes |
|||
* @return Map describing the XAttrs of the file or directory |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public Map<String, byte[]> getXAttrs(Path path) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support getXAttrs"); |
|||
} |
|||
|
|||
/** |
|||
* Get all of the xattrs name/value pairs for a file or directory. |
|||
* Only those xattrs which the logged-in user has permissions to view |
|||
* are returned. |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to get extended attributes |
|||
* @param names XAttr names. |
|||
* @return Map describing the XAttrs of the file or directory |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public Map<String, byte[]> getXAttrs(Path path, List<String> names) |
|||
throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support getXAttrs"); |
|||
} |
|||
|
|||
/** |
|||
* Get all of the xattr names for a file or directory. |
|||
* Only those xattr names which the logged-in user has permissions to view |
|||
* are returned. |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to get extended attributes |
|||
* @return List{@literal <String>} of the XAttr names of the file or directory |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public List<String> listXAttrs(Path path) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support listXAttrs"); |
|||
} |
|||
|
|||
/** |
|||
* Remove an xattr of a file or directory. |
|||
* The name must be prefixed with the namespace followed by ".". For example, |
|||
* "user.attr". |
|||
* <p> |
|||
* Refer to the HDFS extended attributes user documentation for details. |
|||
* |
|||
* @param path Path to remove extended attribute |
|||
* @param name xattr name |
|||
* @throws IOException IO failure |
|||
* @throws UnsupportedOperationException if the operation is unsupported |
|||
* (default outcome). |
|||
*/ |
|||
@Override |
|||
public void removeXAttr(Path path, String name) throws IOException { |
|||
throw new UnsupportedOperationException(getClass().getSimpleName() |
|||
+ " doesn't support removeXAttr"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,270 @@ |
|||
package seaweed.hdfs; |
|||
|
|||
import org.apache.hadoop.fs.FileStatus; |
|||
import org.apache.hadoop.fs.FileSystem; |
|||
import org.apache.hadoop.fs.Path; |
|||
import org.apache.hadoop.fs.permission.FsPermission; |
|||
import org.apache.hadoop.security.UserGroupInformation; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import seaweedfs.client.FilerClient; |
|||
import seaweedfs.client.FilerGrpcClient; |
|||
import seaweedfs.client.FilerProto; |
|||
import seaweedfs.client.SeaweedRead; |
|||
|
|||
import java.io.FileNotFoundException; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
public class SeaweedFileSystemStore { |
|||
|
|||
private static final Logger LOG = LoggerFactory.getLogger(SeaweedFileSystemStore.class); |
|||
|
|||
private FilerGrpcClient filerGrpcClient; |
|||
private FilerClient filerClient; |
|||
|
|||
public SeaweedFileSystemStore(String host, int port) { |
|||
int grpcPort = 10000 + port; |
|||
filerGrpcClient = new FilerGrpcClient(host, grpcPort); |
|||
filerClient = new FilerClient(filerGrpcClient); |
|||
} |
|||
|
|||
public static String getParentDirectory(Path path) { |
|||
return path.isRoot() ? "/" : path.getParent().toUri().getPath(); |
|||
} |
|||
|
|||
static int permissionToMode(FsPermission permission, boolean isDirectory) { |
|||
int p = permission.toShort(); |
|||
if (isDirectory) { |
|||
p = p | 1 << 31; |
|||
} |
|||
return p; |
|||
} |
|||
|
|||
public boolean createDirectory(final Path path, UserGroupInformation currentUser, |
|||
final FsPermission permission, final FsPermission umask) { |
|||
|
|||
LOG.debug("createDirectory path: {} permission: {} umask: {}", |
|||
path, |
|||
permission, |
|||
umask); |
|||
|
|||
return filerClient.mkdirs( |
|||
path.toUri().getPath(), |
|||
permissionToMode(permission, true), |
|||
currentUser.getUserName(), |
|||
currentUser.getGroupNames() |
|||
); |
|||
} |
|||
|
|||
public FileStatus[] listEntries(final Path path) { |
|||
LOG.debug("listEntries path: {}", path); |
|||
|
|||
List<FileStatus> fileStatuses = new ArrayList<FileStatus>(); |
|||
|
|||
List<FilerProto.Entry> entries = filerClient.listEntries(path.toUri().getPath()); |
|||
|
|||
for (FilerProto.Entry entry : entries) { |
|||
|
|||
FileStatus fileStatus = doGetFileStatus(new Path(path, entry.getName()), entry); |
|||
|
|||
fileStatuses.add(fileStatus); |
|||
} |
|||
return fileStatuses.toArray(new FileStatus[0]); |
|||
} |
|||
|
|||
public FileStatus getFileStatus(final Path path) { |
|||
|
|||
FilerProto.Entry entry = lookupEntry(path); |
|||
if (entry == null) { |
|||
return null; |
|||
} |
|||
LOG.debug("doGetFileStatus path:{} entry:{}", path, entry); |
|||
|
|||
FileStatus fileStatus = doGetFileStatus(path, entry); |
|||
return fileStatus; |
|||
} |
|||
|
|||
public boolean deleteEntries(final Path path, boolean isDirectory, boolean recursive) { |
|||
LOG.debug("deleteEntries path: {} isDirectory {} recursive: {}", |
|||
path, |
|||
String.valueOf(isDirectory), |
|||
String.valueOf(recursive)); |
|||
|
|||
if (path.isRoot()) { |
|||
return true; |
|||
} |
|||
|
|||
if (recursive && isDirectory) { |
|||
List<FilerProto.Entry> entries = filerClient.listEntries(path.toUri().getPath()); |
|||
for (FilerProto.Entry entry : entries) { |
|||
deleteEntries(new Path(path, entry.getName()), entry.getIsDirectory(), true); |
|||
} |
|||
} |
|||
|
|||
return filerClient.deleteEntry(getParentDirectory(path), path.getName(), true, recursive, true); |
|||
} |
|||
|
|||
private FileStatus doGetFileStatus(Path path, FilerProto.Entry entry) { |
|||
FilerProto.FuseAttributes attributes = entry.getAttributes(); |
|||
long length = SeaweedRead.totalSize(entry.getChunksList()); |
|||
boolean isDir = entry.getIsDirectory(); |
|||
int block_replication = 1; |
|||
int blocksize = 512; |
|||
long modification_time = attributes.getMtime() * 1000; // milliseconds |
|||
long access_time = 0; |
|||
FsPermission permission = FsPermission.createImmutable((short) attributes.getFileMode()); |
|||
String owner = attributes.getUserName(); |
|||
String group = attributes.getGroupNameCount() > 0 ? attributes.getGroupName(0) : ""; |
|||
return new FileStatus(length, isDir, block_replication, blocksize, |
|||
modification_time, access_time, permission, owner, group, null, path); |
|||
} |
|||
|
|||
private FilerProto.Entry lookupEntry(Path path) { |
|||
|
|||
return filerClient.lookupEntry(getParentDirectory(path), path.getName()); |
|||
|
|||
} |
|||
|
|||
public void rename(Path source, Path destination) { |
|||
|
|||
LOG.debug("rename source: {} destination:{}", source, destination); |
|||
|
|||
if (source.isRoot()) { |
|||
return; |
|||
} |
|||
LOG.info("rename source: {} destination:{}", source, destination); |
|||
FilerProto.Entry entry = lookupEntry(source); |
|||
if (entry == null) { |
|||
LOG.warn("rename non-existing source: {}", source); |
|||
return; |
|||
} |
|||
filerClient.mv(source.toUri().getPath(), destination.toUri().getPath()); |
|||
} |
|||
|
|||
public OutputStream createFile(final Path path, |
|||
final boolean overwrite, |
|||
FsPermission permission, |
|||
int bufferSize, |
|||
String replication) throws IOException { |
|||
|
|||
permission = permission == null ? FsPermission.getFileDefault() : permission; |
|||
|
|||
LOG.debug("createFile path: {} overwrite: {} permission: {}", |
|||
path, |
|||
overwrite, |
|||
permission.toString()); |
|||
|
|||
UserGroupInformation userGroupInformation = UserGroupInformation.getCurrentUser(); |
|||
long now = System.currentTimeMillis() / 1000L; |
|||
|
|||
FilerProto.Entry.Builder entry = null; |
|||
long writePosition = 0; |
|||
if (!overwrite) { |
|||
FilerProto.Entry existingEntry = lookupEntry(path); |
|||
LOG.debug("createFile merged entry path:{} existingEntry:{}", path, existingEntry); |
|||
if (existingEntry != null) { |
|||
entry = FilerProto.Entry.newBuilder(); |
|||
entry.mergeFrom(existingEntry); |
|||
entry.getAttributesBuilder().setMtime(now); |
|||
LOG.debug("createFile merged entry path:{} entry:{} from:{}", path, entry, existingEntry); |
|||
writePosition = SeaweedRead.totalSize(existingEntry.getChunksList()); |
|||
replication = existingEntry.getAttributes().getReplication(); |
|||
} |
|||
} |
|||
if (entry == null) { |
|||
entry = FilerProto.Entry.newBuilder() |
|||
.setName(path.getName()) |
|||
.setIsDirectory(false) |
|||
.setAttributes(FilerProto.FuseAttributes.newBuilder() |
|||
.setFileMode(permissionToMode(permission, false)) |
|||
.setReplication(replication) |
|||
.setCrtime(now) |
|||
.setMtime(now) |
|||
.setUserName(userGroupInformation.getUserName()) |
|||
.clearGroupName() |
|||
.addAllGroupName(Arrays.asList(userGroupInformation.getGroupNames())) |
|||
); |
|||
} |
|||
|
|||
return new SeaweedOutputStream(filerGrpcClient, path, entry, writePosition, bufferSize, replication); |
|||
|
|||
} |
|||
|
|||
public InputStream openFileForRead(final Path path, FileSystem.Statistics statistics, |
|||
int bufferSize) throws IOException { |
|||
|
|||
LOG.debug("openFileForRead path:{} bufferSize:{}", path, bufferSize); |
|||
|
|||
int readAheadQueueDepth = 2; |
|||
FilerProto.Entry entry = lookupEntry(path); |
|||
|
|||
if (entry == null) { |
|||
throw new FileNotFoundException("read non-exist file " + path); |
|||
} |
|||
|
|||
return new SeaweedInputStream(filerGrpcClient, |
|||
statistics, |
|||
path.toUri().getPath(), |
|||
entry, |
|||
bufferSize, |
|||
readAheadQueueDepth); |
|||
} |
|||
|
|||
public void setOwner(Path path, String owner, String group) { |
|||
|
|||
LOG.debug("setOwner path:{} owner:{} group:{}", path, owner, group); |
|||
|
|||
FilerProto.Entry entry = lookupEntry(path); |
|||
if (entry == null) { |
|||
LOG.debug("setOwner path:{} entry:{}", path, entry); |
|||
return; |
|||
} |
|||
|
|||
FilerProto.Entry.Builder entryBuilder = entry.toBuilder(); |
|||
FilerProto.FuseAttributes.Builder attributesBuilder = entry.getAttributes().toBuilder(); |
|||
|
|||
if (owner != null) { |
|||
attributesBuilder.setUserName(owner); |
|||
} |
|||
if (group != null) { |
|||
attributesBuilder.clearGroupName(); |
|||
attributesBuilder.addGroupName(group); |
|||
} |
|||
|
|||
entryBuilder.setAttributes(attributesBuilder); |
|||
|
|||
LOG.debug("setOwner path:{} entry:{}", path, entryBuilder); |
|||
|
|||
filerClient.updateEntry(getParentDirectory(path), entryBuilder.build()); |
|||
|
|||
} |
|||
|
|||
public void setPermission(Path path, FsPermission permission) { |
|||
|
|||
LOG.debug("setPermission path:{} permission:{}", path, permission); |
|||
|
|||
FilerProto.Entry entry = lookupEntry(path); |
|||
if (entry == null) { |
|||
LOG.debug("setPermission path:{} entry:{}", path, entry); |
|||
return; |
|||
} |
|||
|
|||
FilerProto.Entry.Builder entryBuilder = entry.toBuilder(); |
|||
FilerProto.FuseAttributes.Builder attributesBuilder = entry.getAttributes().toBuilder(); |
|||
|
|||
attributesBuilder.setFileMode(permissionToMode(permission, entry.getIsDirectory())); |
|||
|
|||
entryBuilder.setAttributes(attributesBuilder); |
|||
|
|||
LOG.debug("setPermission path:{} entry:{}", path, entryBuilder); |
|||
|
|||
filerClient.updateEntry(getParentDirectory(path), entryBuilder.build()); |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,371 @@ |
|||
package seaweed.hdfs; |
|||
|
|||
// based on org.apache.hadoop.fs.azurebfs.services.AbfsInputStream |
|||
|
|||
import com.google.common.base.Preconditions; |
|||
import org.apache.hadoop.fs.FSExceptionMessages; |
|||
import org.apache.hadoop.fs.FSInputStream; |
|||
import org.apache.hadoop.fs.FileSystem.Statistics; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import seaweedfs.client.FilerGrpcClient; |
|||
import seaweedfs.client.FilerProto; |
|||
import seaweedfs.client.SeaweedRead; |
|||
|
|||
import java.io.EOFException; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
|
|||
public class SeaweedInputStream extends FSInputStream { |
|||
|
|||
private static final Logger LOG = LoggerFactory.getLogger(SeaweedInputStream.class); |
|||
|
|||
private final FilerGrpcClient filerGrpcClient; |
|||
private final Statistics statistics; |
|||
private final String path; |
|||
private final FilerProto.Entry entry; |
|||
private final List<SeaweedRead.VisibleInterval> visibleIntervalList; |
|||
private final long contentLength; |
|||
private final int bufferSize; // default buffer size |
|||
private final int readAheadQueueDepth; // initialized in constructor |
|||
private final boolean readAheadEnabled; // whether enable readAhead; |
|||
|
|||
private byte[] buffer = null; // will be initialized on first use |
|||
|
|||
private long fCursor = 0; // cursor of buffer within file - offset of next byte to read from remote server |
|||
private long fCursorAfterLastRead = -1; |
|||
private int bCursor = 0; // cursor of read within buffer - offset of next byte to be returned from buffer |
|||
private int limit = 0; // offset of next byte to be read into buffer from service (i.e., upper marker+1 |
|||
// of valid bytes in buffer) |
|||
private boolean closed = false; |
|||
|
|||
public SeaweedInputStream( |
|||
final FilerGrpcClient filerGrpcClient, |
|||
final Statistics statistics, |
|||
final String path, |
|||
final FilerProto.Entry entry, |
|||
final int bufferSize, |
|||
final int readAheadQueueDepth) { |
|||
this.filerGrpcClient = filerGrpcClient; |
|||
this.statistics = statistics; |
|||
this.path = path; |
|||
this.entry = entry; |
|||
this.contentLength = SeaweedRead.totalSize(entry.getChunksList()); |
|||
this.bufferSize = bufferSize; |
|||
this.readAheadQueueDepth = (readAheadQueueDepth >= 0) ? readAheadQueueDepth : Runtime.getRuntime().availableProcessors(); |
|||
this.readAheadEnabled = true; |
|||
|
|||
this.visibleIntervalList = SeaweedRead.nonOverlappingVisibleIntervals(entry.getChunksList()); |
|||
|
|||
LOG.debug("new path:{} entry:{} visibleIntervalList:{}", path, entry, visibleIntervalList); |
|||
|
|||
} |
|||
|
|||
public String getPath() { |
|||
return path; |
|||
} |
|||
|
|||
@Override |
|||
public int read() throws IOException { |
|||
byte[] b = new byte[1]; |
|||
int numberOfBytesRead = read(b, 0, 1); |
|||
if (numberOfBytesRead < 0) { |
|||
return -1; |
|||
} else { |
|||
return (b[0] & 0xFF); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public synchronized int read(final byte[] b, final int off, final int len) throws IOException { |
|||
int currentOff = off; |
|||
int currentLen = len; |
|||
int lastReadBytes; |
|||
int totalReadBytes = 0; |
|||
do { |
|||
lastReadBytes = readOneBlock(b, currentOff, currentLen); |
|||
if (lastReadBytes > 0) { |
|||
currentOff += lastReadBytes; |
|||
currentLen -= lastReadBytes; |
|||
totalReadBytes += lastReadBytes; |
|||
} |
|||
if (currentLen <= 0 || currentLen > b.length - currentOff) { |
|||
break; |
|||
} |
|||
} while (lastReadBytes > 0); |
|||
return totalReadBytes > 0 ? totalReadBytes : lastReadBytes; |
|||
} |
|||
|
|||
private int readOneBlock(final byte[] b, final int off, final int len) throws IOException { |
|||
if (closed) { |
|||
throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
|
|||
Preconditions.checkNotNull(b); |
|||
|
|||
if (len == 0) { |
|||
return 0; |
|||
} |
|||
|
|||
if (this.available() == 0) { |
|||
return -1; |
|||
} |
|||
|
|||
if (off < 0 || len < 0 || len > b.length - off) { |
|||
throw new IndexOutOfBoundsException(); |
|||
} |
|||
|
|||
//If buffer is empty, then fill the buffer. |
|||
if (bCursor == limit) { |
|||
//If EOF, then return -1 |
|||
if (fCursor >= contentLength) { |
|||
return -1; |
|||
} |
|||
|
|||
long bytesRead = 0; |
|||
//reset buffer to initial state - i.e., throw away existing data |
|||
bCursor = 0; |
|||
limit = 0; |
|||
if (buffer == null) { |
|||
buffer = new byte[bufferSize]; |
|||
} |
|||
|
|||
// Enable readAhead when reading sequentially |
|||
if (-1 == fCursorAfterLastRead || fCursorAfterLastRead == fCursor || b.length >= bufferSize) { |
|||
bytesRead = readInternal(fCursor, buffer, 0, bufferSize, false); |
|||
} else { |
|||
bytesRead = readInternal(fCursor, buffer, 0, b.length, true); |
|||
} |
|||
|
|||
if (bytesRead == -1) { |
|||
return -1; |
|||
} |
|||
|
|||
limit += bytesRead; |
|||
fCursor += bytesRead; |
|||
fCursorAfterLastRead = fCursor; |
|||
} |
|||
|
|||
//If there is anything in the buffer, then return lesser of (requested bytes) and (bytes in buffer) |
|||
//(bytes returned may be less than requested) |
|||
int bytesRemaining = limit - bCursor; |
|||
int bytesToRead = Math.min(len, bytesRemaining); |
|||
System.arraycopy(buffer, bCursor, b, off, bytesToRead); |
|||
bCursor += bytesToRead; |
|||
if (statistics != null) { |
|||
statistics.incrementBytesRead(bytesToRead); |
|||
} |
|||
return bytesToRead; |
|||
} |
|||
|
|||
|
|||
private int readInternal(final long position, final byte[] b, final int offset, final int length, |
|||
final boolean bypassReadAhead) throws IOException { |
|||
if (readAheadEnabled && !bypassReadAhead) { |
|||
// try reading from read-ahead |
|||
if (offset != 0) { |
|||
throw new IllegalArgumentException("readahead buffers cannot have non-zero buffer offsets"); |
|||
} |
|||
int receivedBytes; |
|||
|
|||
// queue read-aheads |
|||
int numReadAheads = this.readAheadQueueDepth; |
|||
long nextSize; |
|||
long nextOffset = position; |
|||
while (numReadAheads > 0 && nextOffset < contentLength) { |
|||
nextSize = Math.min((long) bufferSize, contentLength - nextOffset); |
|||
ReadBufferManager.getBufferManager().queueReadAhead(this, nextOffset, (int) nextSize); |
|||
nextOffset = nextOffset + nextSize; |
|||
numReadAheads--; |
|||
} |
|||
|
|||
// try reading from buffers first |
|||
receivedBytes = ReadBufferManager.getBufferManager().getBlock(this, position, length, b); |
|||
if (receivedBytes > 0) { |
|||
return receivedBytes; |
|||
} |
|||
|
|||
// got nothing from read-ahead, do our own read now |
|||
receivedBytes = readRemote(position, b, offset, length); |
|||
return receivedBytes; |
|||
} else { |
|||
return readRemote(position, b, offset, length); |
|||
} |
|||
} |
|||
|
|||
int readRemote(long position, byte[] b, int offset, int length) throws IOException { |
|||
if (position < 0) { |
|||
throw new IllegalArgumentException("attempting to read from negative offset"); |
|||
} |
|||
if (position >= contentLength) { |
|||
return -1; // Hadoop prefers -1 to EOFException |
|||
} |
|||
if (b == null) { |
|||
throw new IllegalArgumentException("null byte array passed in to read() method"); |
|||
} |
|||
if (offset >= b.length) { |
|||
throw new IllegalArgumentException("offset greater than length of array"); |
|||
} |
|||
if (length < 0) { |
|||
throw new IllegalArgumentException("requested read length is less than zero"); |
|||
} |
|||
if (length > (b.length - offset)) { |
|||
throw new IllegalArgumentException("requested read length is more than will fit after requested offset in buffer"); |
|||
} |
|||
|
|||
long bytesRead = SeaweedRead.read(filerGrpcClient, visibleIntervalList, position, b, offset, length); |
|||
if (bytesRead > Integer.MAX_VALUE) { |
|||
throw new IOException("Unexpected Content-Length"); |
|||
} |
|||
return (int) bytesRead; |
|||
} |
|||
|
|||
/** |
|||
* Seek to given position in stream. |
|||
* |
|||
* @param n position to seek to |
|||
* @throws IOException if there is an error |
|||
* @throws EOFException if attempting to seek past end of file |
|||
*/ |
|||
@Override |
|||
public synchronized void seek(long n) throws IOException { |
|||
if (closed) { |
|||
throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
if (n < 0) { |
|||
throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK); |
|||
} |
|||
if (n > contentLength) { |
|||
throw new EOFException(FSExceptionMessages.CANNOT_SEEK_PAST_EOF); |
|||
} |
|||
|
|||
if (n >= fCursor - limit && n <= fCursor) { // within buffer |
|||
bCursor = (int) (n - (fCursor - limit)); |
|||
return; |
|||
} |
|||
|
|||
// next read will read from here |
|||
fCursor = n; |
|||
|
|||
//invalidate buffer |
|||
limit = 0; |
|||
bCursor = 0; |
|||
} |
|||
|
|||
@Override |
|||
public synchronized long skip(long n) throws IOException { |
|||
if (closed) { |
|||
throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
long currentPos = getPos(); |
|||
if (currentPos == contentLength) { |
|||
if (n > 0) { |
|||
throw new EOFException(FSExceptionMessages.CANNOT_SEEK_PAST_EOF); |
|||
} |
|||
} |
|||
long newPos = currentPos + n; |
|||
if (newPos < 0) { |
|||
newPos = 0; |
|||
n = newPos - currentPos; |
|||
} |
|||
if (newPos > contentLength) { |
|||
newPos = contentLength; |
|||
n = newPos - currentPos; |
|||
} |
|||
seek(newPos); |
|||
return n; |
|||
} |
|||
|
|||
/** |
|||
* Return the size of the remaining available bytes |
|||
* if the size is less than or equal to {@link Integer#MAX_VALUE}, |
|||
* otherwise, return {@link Integer#MAX_VALUE}. |
|||
* <p> |
|||
* This is to match the behavior of DFSInputStream.available(), |
|||
* which some clients may rely on (HBase write-ahead log reading in |
|||
* particular). |
|||
*/ |
|||
@Override |
|||
public synchronized int available() throws IOException { |
|||
if (closed) { |
|||
throw new IOException( |
|||
FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
final long remaining = this.contentLength - this.getPos(); |
|||
return remaining <= Integer.MAX_VALUE |
|||
? (int) remaining : Integer.MAX_VALUE; |
|||
} |
|||
|
|||
/** |
|||
* Returns the length of the file that this stream refers to. Note that the length returned is the length |
|||
* as of the time the Stream was opened. Specifically, if there have been subsequent appends to the file, |
|||
* they wont be reflected in the returned length. |
|||
* |
|||
* @return length of the file. |
|||
* @throws IOException if the stream is closed |
|||
*/ |
|||
public long length() throws IOException { |
|||
if (closed) { |
|||
throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
return contentLength; |
|||
} |
|||
|
|||
/** |
|||
* Return the current offset from the start of the file |
|||
* |
|||
* @throws IOException throws {@link IOException} if there is an error |
|||
*/ |
|||
@Override |
|||
public synchronized long getPos() throws IOException { |
|||
if (closed) { |
|||
throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|||
} |
|||
return fCursor - limit + bCursor; |
|||
} |
|||
|
|||
/** |
|||
* Seeks a different copy of the data. Returns true if |
|||
* found a new source, false otherwise. |
|||
* |
|||
* @throws IOException throws {@link IOException} if there is an error |
|||
*/ |
|||
@Override |
|||
public boolean seekToNewSource(long l) throws IOException { |
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
public synchronized void close() throws IOException { |
|||
closed = true; |
|||
buffer = null; // de-reference the buffer so it can be GC'ed sooner |
|||
} |
|||
|
|||
/** |
|||
* Not supported by this stream. Throws {@link UnsupportedOperationException} |
|||
* |
|||
* @param readlimit ignored |
|||
*/ |
|||
@Override |
|||
public synchronized void mark(int readlimit) { |
|||
throw new UnsupportedOperationException("mark()/reset() not supported on this stream"); |
|||
} |
|||
|
|||
/** |
|||
* Not supported by this stream. Throws {@link UnsupportedOperationException} |
|||
*/ |
|||
@Override |
|||
public synchronized void reset() throws IOException { |
|||
throw new UnsupportedOperationException("mark()/reset() not supported on this stream"); |
|||
} |
|||
|
|||
/** |
|||
* gets whether mark and reset are supported by {@code ADLFileInputStream}. Always returns false. |
|||
* |
|||
* @return always {@code false} |
|||
*/ |
|||
@Override |
|||
public boolean markSupported() { |
|||
return false; |
|||
} |
|||
} |
@ -0,0 +1,95 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"path/filepath" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
"github.com/chrislusf/seaweedfs/weed/storage" |
|||
"github.com/chrislusf/seaweedfs/weed/storage/backend" |
|||
"github.com/chrislusf/seaweedfs/weed/storage/needle" |
|||
"github.com/chrislusf/seaweedfs/weed/storage/super_block" |
|||
) |
|||
|
|||
var ( |
|||
volumePath = flag.String("dir", "/tmp", "data directory to store files") |
|||
volumeCollection = flag.String("collection", "", "the volume collection name") |
|||
volumeId = flag.Int("volumeId", -1, "a volume id. The volume should already exist in the dir. The volume index file should not exist.") |
|||
) |
|||
|
|||
func Checksum(n *needle.Needle) string { |
|||
return fmt.Sprintf("%s%x", n.Id, n.Cookie) |
|||
} |
|||
|
|||
type VolumeFileScanner4SeeDat struct { |
|||
version needle.Version |
|||
block super_block.SuperBlock |
|||
|
|||
dir string |
|||
hashes map[string]bool |
|||
dat *os.File |
|||
datBackend backend.BackendStorageFile |
|||
} |
|||
|
|||
func (scanner *VolumeFileScanner4SeeDat) VisitSuperBlock(superBlock super_block.SuperBlock) error { |
|||
scanner.version = superBlock.Version |
|||
scanner.block = superBlock |
|||
return nil |
|||
|
|||
} |
|||
func (scanner *VolumeFileScanner4SeeDat) ReadNeedleBody() bool { |
|||
return true |
|||
} |
|||
|
|||
func (scanner *VolumeFileScanner4SeeDat) VisitNeedle(n *needle.Needle, offset int64, needleHeader, needleBody []byte) error { |
|||
|
|||
if scanner.datBackend == nil { |
|||
newFileName := filepath.Join(*volumePath, "dat_fixed") |
|||
newDatFile, err := os.Create(newFileName) |
|||
if err != nil { |
|||
glog.Fatalf("Write New Volume Data %v", err) |
|||
} |
|||
scanner.datBackend = backend.NewDiskFile(newDatFile) |
|||
scanner.datBackend.WriteAt(scanner.block.Bytes(), 0) |
|||
} |
|||
|
|||
checksum := Checksum(n) |
|||
|
|||
if scanner.hashes[checksum] { |
|||
glog.V(0).Infof("duplicate checksum:%s fid:%d,%s%x @ offset:%d", checksum, *volumeId, n.Id, n.Cookie, offset) |
|||
return nil |
|||
} |
|||
scanner.hashes[checksum] = true |
|||
|
|||
_, s, _, e := n.Append(scanner.datBackend, scanner.version) |
|||
fmt.Printf("size %d error %v\n", s, e) |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func main() { |
|||
flag.Parse() |
|||
|
|||
vid := needle.VolumeId(*volumeId) |
|||
|
|||
outpath, _ := filepath.Abs(filepath.Dir(os.Args[0])) |
|||
|
|||
scanner := &VolumeFileScanner4SeeDat{ |
|||
dir: filepath.Join(outpath, "out"), |
|||
hashes: map[string]bool{}, |
|||
} |
|||
|
|||
if _, err := os.Stat(scanner.dir); err != nil { |
|||
if err := os.MkdirAll(scanner.dir, os.ModePerm); err != nil { |
|||
glog.Fatalf("could not create output dir : %s", err) |
|||
} |
|||
} |
|||
|
|||
err := storage.ScanVolumeFile(*volumePath, *volumeCollection, vid, storage.NeedleMapInMemory, scanner) |
|||
if err != nil { |
|||
glog.Fatalf("Reading Volume File [ERROR] %s\n", err) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,13 @@ |
|||
package command |
|||
|
|||
import ( |
|||
"github.com/seaweedfs/fuse" |
|||
) |
|||
|
|||
func osSpecificMountOptions() []fuse.MountOption { |
|||
return []fuse.MountOption{} |
|||
} |
|||
|
|||
func checkMountPointAvailable(dir string) bool { |
|||
return true |
|||
} |
@ -0,0 +1,13 @@ |
|||
package command |
|||
|
|||
import ( |
|||
"github.com/seaweedfs/fuse" |
|||
) |
|||
|
|||
func osSpecificMountOptions() []fuse.MountOption { |
|||
return []fuse.MountOption{} |
|||
} |
|||
|
|||
func checkMountPointAvailable(dir string) bool { |
|||
return true |
|||
} |
@ -0,0 +1,157 @@ |
|||
package command |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"io" |
|||
"os" |
|||
"strings" |
|||
|
|||
"github.com/seaweedfs/fuse" |
|||
) |
|||
|
|||
const ( |
|||
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue |
|||
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) |
|||
|
|||
(1) mount ID: unique identifier of the mount (may be reused after umount) |
|||
(2) parent ID: ID of parent (or of self for the top of the mount tree) |
|||
(3) major:minor: value of st_dev for files on filesystem |
|||
(4) root: root of the mount within the filesystem |
|||
(5) mount point: mount point relative to the process's root |
|||
(6) mount options: per mount options |
|||
(7) optional fields: zero or more fields of the form "tag[:value]" |
|||
(8) separator: marks the end of the optional fields |
|||
(9) filesystem type: name of filesystem of the form "type[.subtype]" |
|||
(10) mount source: filesystem specific information or "none" |
|||
(11) super options: per super block options*/ |
|||
mountinfoFormat = "%d %d %d:%d %s %s %s %s" |
|||
) |
|||
|
|||
// Info reveals information about a particular mounted filesystem. This
|
|||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
|||
type Info struct { |
|||
// ID is a unique identifier of the mount (may be reused after umount).
|
|||
ID int |
|||
|
|||
// Parent indicates the ID of the mount parent (or of self for the top of the
|
|||
// mount tree).
|
|||
Parent int |
|||
|
|||
// Major indicates one half of the device ID which identifies the device class.
|
|||
Major int |
|||
|
|||
// Minor indicates one half of the device ID which identifies a specific
|
|||
// instance of device.
|
|||
Minor int |
|||
|
|||
// Root of the mount within the filesystem.
|
|||
Root string |
|||
|
|||
// Mountpoint indicates the mount point relative to the process's root.
|
|||
Mountpoint string |
|||
|
|||
// Opts represents mount-specific options.
|
|||
Opts string |
|||
|
|||
// Optional represents optional fields.
|
|||
Optional string |
|||
|
|||
// Fstype indicates the type of filesystem, such as EXT3.
|
|||
Fstype string |
|||
|
|||
// Source indicates filesystem specific information or "none".
|
|||
Source string |
|||
|
|||
// VfsOpts represents per super block options.
|
|||
VfsOpts string |
|||
} |
|||
|
|||
// Mounted determines if a specified mountpoint has been mounted.
|
|||
// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab.
|
|||
func mounted(mountPoint string) (bool, error) { |
|||
entries, err := parseMountTable() |
|||
if err != nil { |
|||
return false, err |
|||
} |
|||
|
|||
// Search the table for the mountPoint
|
|||
for _, e := range entries { |
|||
if e.Mountpoint == mountPoint { |
|||
return true, nil |
|||
} |
|||
} |
|||
return false, nil |
|||
} |
|||
|
|||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
|||
// bind mounts
|
|||
func parseMountTable() ([]*Info, error) { |
|||
f, err := os.Open("/proc/self/mountinfo") |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
defer f.Close() |
|||
|
|||
return parseInfoFile(f) |
|||
} |
|||
|
|||
func parseInfoFile(r io.Reader) ([]*Info, error) { |
|||
var ( |
|||
s = bufio.NewScanner(r) |
|||
out []*Info |
|||
) |
|||
|
|||
for s.Scan() { |
|||
if err := s.Err(); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
var ( |
|||
p = &Info{} |
|||
text = s.Text() |
|||
optionalFields string |
|||
) |
|||
|
|||
if _, err := fmt.Sscanf(text, mountinfoFormat, |
|||
&p.ID, &p.Parent, &p.Major, &p.Minor, |
|||
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { |
|||
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) |
|||
} |
|||
// Safe as mountinfo encodes mountpoints with spaces as \040.
|
|||
index := strings.Index(text, " - ") |
|||
postSeparatorFields := strings.Fields(text[index+3:]) |
|||
if len(postSeparatorFields) < 3 { |
|||
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) |
|||
} |
|||
|
|||
if optionalFields != "-" { |
|||
p.Optional = optionalFields |
|||
} |
|||
|
|||
p.Fstype = postSeparatorFields[0] |
|||
p.Source = postSeparatorFields[1] |
|||
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") |
|||
out = append(out, p) |
|||
} |
|||
return out, nil |
|||
} |
|||
|
|||
func osSpecificMountOptions() []fuse.MountOption { |
|||
return []fuse.MountOption{ |
|||
fuse.AllowNonEmptyMount(), |
|||
} |
|||
} |
|||
|
|||
func checkMountPointAvailable(dir string) bool { |
|||
mountPoint := dir |
|||
if mountPoint != "/" && strings.HasSuffix(mountPoint, "/") { |
|||
mountPoint = mountPoint[0 : len(mountPoint)-1] |
|||
} |
|||
|
|||
if mounted, err := mounted(mountPoint); err != nil || mounted { |
|||
return false |
|||
} |
|||
|
|||
return true |
|||
} |
@ -0,0 +1,44 @@ |
|||
package command |
|||
|
|||
import ( |
|||
"bytes" |
|||
"fmt" |
|||
"testing" |
|||
|
|||
"github.com/spf13/viper" |
|||
) |
|||
|
|||
func TestReadingTomlConfiguration(t *testing.T) { |
|||
|
|||
viper.SetConfigType("toml") |
|||
|
|||
// any approach to require this configuration into your program.
|
|||
var tomlExample = []byte(` |
|||
[database] |
|||
server = "192.168.1.1" |
|||
ports = [ 8001, 8001, 8002 ] |
|||
connection_max = 5000 |
|||
enabled = true |
|||
|
|||
[servers] |
|||
|
|||
# You can indent as you please. Tabs or spaces. TOML don't care. |
|||
[servers.alpha] |
|||
ip = "10.0.0.1" |
|||
dc = "eqdc10" |
|||
|
|||
[servers.beta] |
|||
ip = "10.0.0.2" |
|||
dc = "eqdc10" |
|||
|
|||
`) |
|||
|
|||
viper.ReadConfig(bytes.NewBuffer(tomlExample)) |
|||
|
|||
fmt.Printf("database is %v\n", viper.Get("database")) |
|||
fmt.Printf("servers is %v\n", viper.GetStringMap("servers")) |
|||
|
|||
alpha := viper.Sub("servers.alpha") |
|||
|
|||
fmt.Printf("alpha ip is %v\n", alpha.GetString("ip")) |
|||
} |
@ -1,84 +0,0 @@ |
|||
Mount the SeaweedFS via FUSE |
|||
|
|||
# Mount by fstab |
|||
|
|||
|
|||
``` |
|||
$ # on linux |
|||
$ sudo apt-get install fuse |
|||
$ sudo echo 'user_allow_other' >> /etc/fuse.conf |
|||
$ sudo mv weedfuse /sbin/mount.weedfuse |
|||
|
|||
$ # on Mac |
|||
$ sudo mv weedfuse /sbin/mount_weedfuse |
|||
|
|||
``` |
|||
|
|||
On both OS X and Linux, you can add one of the entries to your /etc/fstab file like the following: |
|||
|
|||
``` |
|||
# mount the whole SeaweedFS |
|||
localhost:8888/ /home/some/mount/folder weedfuse |
|||
|
|||
# mount the SeaweedFS sub folder |
|||
localhost:8888/sub/dir /home/some/mount/folder weedfuse |
|||
|
|||
# mount the SeaweedFS sub folder with some options |
|||
localhost:8888/sub/dir /home/some/mount/folder weedfuse user |
|||
|
|||
``` |
|||
|
|||
To verify it can work, try this command |
|||
``` |
|||
$ sudo mount -av |
|||
|
|||
... |
|||
|
|||
/home/some/mount/folder : successfully mounted |
|||
|
|||
``` |
|||
|
|||
If you see `successfully mounted`, try to access the mounted folder and verify everything works. |
|||
|
|||
|
|||
To debug, run these: |
|||
``` |
|||
|
|||
$ weedfuse -foreground localhost:8888/ /home/some/mount/folder |
|||
|
|||
``` |
|||
|
|||
|
|||
To unmount the folder: |
|||
``` |
|||
|
|||
$ sudo umount /home/some/mount/folder |
|||
|
|||
``` |
|||
|
|||
<!-- not working yet! |
|||
|
|||
# Mount by autofs |
|||
|
|||
AutoFS can mount a folder if accessed. |
|||
|
|||
``` |
|||
# install autofs |
|||
$ sudo apt-get install autofs |
|||
``` |
|||
|
|||
Here is an example on how to mount a folder for all users under `/home` directory. |
|||
Assuming there exists corresponding folders under `/home` on both local and SeaweedFS. |
|||
|
|||
Edit `/etc/auto.master` and `/etc/auto.weedfuse` file with these content |
|||
``` |
|||
$ cat /etc/auto.master |
|||
/home /etc/auto.weedfuse |
|||
|
|||
$ cat /etc/auto.weedfuse |
|||
# map /home/<user> to localhost:8888/home/<user> |
|||
* -fstype=weedfuse,rw,allow_other,foreground :localhost\:8888/home/& |
|||
|
|||
``` |
|||
|
|||
--> |
@ -1,109 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"strings" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/command" |
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
"github.com/jacobsa/daemonize" |
|||
"github.com/kardianos/osext" |
|||
) |
|||
|
|||
var ( |
|||
fuseCommand = flag.NewFlagSet("weedfuse", flag.ContinueOnError) |
|||
options = fuseCommand.String("o", "", "comma separated options rw,uid=xxx,gid=xxx") |
|||
isForeground = fuseCommand.Bool("foreground", false, "starts as a daemon") |
|||
) |
|||
|
|||
func main() { |
|||
|
|||
err := fuseCommand.Parse(os.Args[1:]) |
|||
if err != nil { |
|||
glog.Fatal(err) |
|||
} |
|||
fmt.Printf("options: %v\n", *options) |
|||
|
|||
// seems this value is always empty, need to parse it differently
|
|||
optionsString := *options |
|||
prev := "" |
|||
for i, arg := range os.Args { |
|||
fmt.Printf("args[%d]: %v\n", i, arg) |
|||
if prev == "-o" { |
|||
optionsString = arg |
|||
} |
|||
prev = arg |
|||
} |
|||
|
|||
device := fuseCommand.Arg(0) |
|||
mountPoint := fuseCommand.Arg(1) |
|||
|
|||
fmt.Printf("source: %v\n", device) |
|||
fmt.Printf("target: %v\n", mountPoint) |
|||
|
|||
nouser := true |
|||
for _, option := range strings.Split(optionsString, ",") { |
|||
fmt.Printf("option: %v\n", option) |
|||
switch option { |
|||
case "user": |
|||
nouser = false |
|||
} |
|||
} |
|||
|
|||
maybeSetupPath() |
|||
|
|||
if !*isForeground { |
|||
startAsDaemon() |
|||
return |
|||
} |
|||
|
|||
parts := strings.SplitN(device, "/", 2) |
|||
filer, filerPath := parts[0], parts[1] |
|||
|
|||
command.RunMount( |
|||
filer, "/"+filerPath, mountPoint, "", "000", "", |
|||
4, !nouser, 0, 1000000) |
|||
|
|||
} |
|||
|
|||
func maybeSetupPath() { |
|||
// sudo mount -av may not include PATH in some linux, e.g., Ubuntu
|
|||
hasPathEnv := false |
|||
for _, e := range os.Environ() { |
|||
if strings.HasPrefix(e, "PATH=") { |
|||
hasPathEnv = true |
|||
} |
|||
fmt.Println(e) |
|||
} |
|||
if !hasPathEnv { |
|||
os.Setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") |
|||
} |
|||
} |
|||
|
|||
func startAsDaemon() { |
|||
|
|||
// adapted from gcsfuse
|
|||
|
|||
// Find the executable.
|
|||
var path string |
|||
path, err := osext.Executable() |
|||
if err != nil { |
|||
glog.Fatalf("osext.Executable: %v", err) |
|||
} |
|||
|
|||
// Set up arguments. Be sure to use foreground mode.
|
|||
args := append([]string{"-foreground"}, os.Args[1:]...) |
|||
|
|||
// Pass along PATH so that the daemon can find fusermount on Linux.
|
|||
env := []string{ |
|||
fmt.Sprintf("PATH=%s", os.Getenv("PATH")), |
|||
} |
|||
|
|||
err = daemonize.Run(path, args, env, os.Stdout) |
|||
if err != nil { |
|||
glog.Fatalf("daemonize.Run: %v", err) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,196 @@ |
|||
package etcd |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"strings" |
|||
"time" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/filer2" |
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
weed_util "github.com/chrislusf/seaweedfs/weed/util" |
|||
"go.etcd.io/etcd/clientv3" |
|||
) |
|||
|
|||
const ( |
|||
DIR_FILE_SEPARATOR = byte(0x00) |
|||
) |
|||
|
|||
func init() { |
|||
filer2.Stores = append(filer2.Stores, &EtcdStore{}) |
|||
} |
|||
|
|||
type EtcdStore struct { |
|||
client *clientv3.Client |
|||
} |
|||
|
|||
func (store *EtcdStore) GetName() string { |
|||
return "etcd" |
|||
} |
|||
|
|||
func (store *EtcdStore) Initialize(configuration weed_util.Configuration) (err error) { |
|||
servers := configuration.GetString("servers") |
|||
if servers == "" { |
|||
servers = "localhost:2379" |
|||
} |
|||
|
|||
timeout := configuration.GetString("timeout") |
|||
if timeout == "" { |
|||
timeout = "3s" |
|||
} |
|||
|
|||
return store.initialize(servers, timeout) |
|||
} |
|||
|
|||
func (store *EtcdStore) initialize(servers string, timeout string) (err error) { |
|||
glog.Infof("filer store etcd: %s", servers) |
|||
|
|||
to, err := time.ParseDuration(timeout) |
|||
if err != nil { |
|||
return fmt.Errorf("parse timeout %s: %s", timeout, err) |
|||
} |
|||
|
|||
store.client, err = clientv3.New(clientv3.Config{ |
|||
Endpoints: strings.Split(servers, ","), |
|||
DialTimeout: to, |
|||
}) |
|||
if err != nil { |
|||
return fmt.Errorf("connect to etcd %s: %s", servers, err) |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
func (store *EtcdStore) BeginTransaction(ctx context.Context) (context.Context, error) { |
|||
return ctx, nil |
|||
} |
|||
func (store *EtcdStore) CommitTransaction(ctx context.Context) error { |
|||
return nil |
|||
} |
|||
func (store *EtcdStore) RollbackTransaction(ctx context.Context) error { |
|||
return nil |
|||
} |
|||
|
|||
func (store *EtcdStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
key := genKey(entry.DirAndName()) |
|||
|
|||
value, err := entry.EncodeAttributesAndChunks() |
|||
if err != nil { |
|||
return fmt.Errorf("encoding %s %+v: %v", entry.FullPath, entry.Attr, err) |
|||
} |
|||
|
|||
if _, err := store.client.Put(ctx, string(key), string(value)); err != nil { |
|||
return fmt.Errorf("persisting %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *EtcdStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
return store.InsertEntry(ctx, entry) |
|||
} |
|||
|
|||
func (store *EtcdStore) FindEntry(ctx context.Context, fullpath filer2.FullPath) (entry *filer2.Entry, err error) { |
|||
key := genKey(fullpath.DirAndName()) |
|||
|
|||
resp, err := store.client.Get(ctx, string(key)) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("get %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
if len(resp.Kvs) == 0 { |
|||
return nil, filer2.ErrNotFound |
|||
} |
|||
|
|||
entry = &filer2.Entry{ |
|||
FullPath: fullpath, |
|||
} |
|||
err = entry.DecodeAttributesAndChunks(resp.Kvs[0].Value) |
|||
if err != nil { |
|||
return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
return entry, nil |
|||
} |
|||
|
|||
func (store *EtcdStore) DeleteEntry(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
key := genKey(fullpath.DirAndName()) |
|||
|
|||
if _, err := store.client.Delete(ctx, string(key)); err != nil { |
|||
return fmt.Errorf("delete %s : %v", fullpath, err) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *EtcdStore) DeleteFolderChildren(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
directoryPrefix := genDirectoryKeyPrefix(fullpath, "") |
|||
|
|||
if _, err := store.client.Delete(ctx, string(directoryPrefix), clientv3.WithPrefix()); err != nil { |
|||
return fmt.Errorf("deleteFolderChildren %s : %v", fullpath, err) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *EtcdStore) ListDirectoryEntries( |
|||
ctx context.Context, fullpath filer2.FullPath, startFileName string, inclusive bool, limit int, |
|||
) (entries []*filer2.Entry, err error) { |
|||
directoryPrefix := genDirectoryKeyPrefix(fullpath, "") |
|||
|
|||
resp, err := store.client.Get(ctx, string(directoryPrefix), |
|||
clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("list %s : %v", fullpath, err) |
|||
} |
|||
|
|||
for _, kv := range resp.Kvs { |
|||
fileName := getNameFromKey(kv.Key) |
|||
if fileName == "" { |
|||
continue |
|||
} |
|||
if fileName == startFileName && !inclusive { |
|||
continue |
|||
} |
|||
limit-- |
|||
if limit < 0 { |
|||
break |
|||
} |
|||
entry := &filer2.Entry{ |
|||
FullPath: filer2.NewFullPath(string(fullpath), fileName), |
|||
} |
|||
if decodeErr := entry.DecodeAttributesAndChunks(kv.Value); decodeErr != nil { |
|||
err = decodeErr |
|||
glog.V(0).Infof("list %s : %v", entry.FullPath, err) |
|||
break |
|||
} |
|||
entries = append(entries, entry) |
|||
} |
|||
|
|||
return entries, err |
|||
} |
|||
|
|||
func genKey(dirPath, fileName string) (key []byte) { |
|||
key = []byte(dirPath) |
|||
key = append(key, DIR_FILE_SEPARATOR) |
|||
key = append(key, []byte(fileName)...) |
|||
return key |
|||
} |
|||
|
|||
func genDirectoryKeyPrefix(fullpath filer2.FullPath, startFileName string) (keyPrefix []byte) { |
|||
keyPrefix = []byte(string(fullpath)) |
|||
keyPrefix = append(keyPrefix, DIR_FILE_SEPARATOR) |
|||
if len(startFileName) > 0 { |
|||
keyPrefix = append(keyPrefix, []byte(startFileName)...) |
|||
} |
|||
return keyPrefix |
|||
} |
|||
|
|||
func getNameFromKey(key []byte) string { |
|||
sepIndex := len(key) - 1 |
|||
for sepIndex >= 0 && key[sepIndex] != DIR_FILE_SEPARATOR { |
|||
sepIndex-- |
|||
} |
|||
|
|||
return string(key[sepIndex+1:]) |
|||
} |
@ -0,0 +1,102 @@ |
|||
package filer2 |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb" |
|||
) |
|||
|
|||
func (f *Filer) DeleteEntryMetaAndData(ctx context.Context, p FullPath, isRecursive bool, ignoreRecursiveError, shouldDeleteChunks bool) (err error) { |
|||
if p == "/" { |
|||
return nil |
|||
} |
|||
|
|||
entry, findErr := f.FindEntry(ctx, p) |
|||
if findErr != nil { |
|||
return findErr |
|||
} |
|||
|
|||
var chunks []*filer_pb.FileChunk |
|||
chunks = append(chunks, entry.Chunks...) |
|||
if entry.IsDirectory() { |
|||
// delete the folder children, not including the folder itself
|
|||
var dirChunks []*filer_pb.FileChunk |
|||
dirChunks, err = f.doBatchDeleteFolderMetaAndData(ctx, entry, isRecursive, ignoreRecursiveError, shouldDeleteChunks) |
|||
if err != nil { |
|||
return fmt.Errorf("delete directory %s: %v", p, err) |
|||
} |
|||
chunks = append(chunks, dirChunks...) |
|||
f.cacheDelDirectory(string(p)) |
|||
} |
|||
// delete the file or folder
|
|||
err = f.doDeleteEntryMetaAndData(ctx, entry, shouldDeleteChunks) |
|||
if err != nil { |
|||
return fmt.Errorf("delete file %s: %v", p, err) |
|||
} |
|||
|
|||
if shouldDeleteChunks { |
|||
go f.DeleteChunks(chunks) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (f *Filer) doBatchDeleteFolderMetaAndData(ctx context.Context, entry *Entry, isRecursive bool, ignoreRecursiveError, shouldDeleteChunks bool) (chunks []*filer_pb.FileChunk, err error) { |
|||
|
|||
lastFileName := "" |
|||
includeLastFile := false |
|||
for { |
|||
entries, err := f.ListDirectoryEntries(ctx, entry.FullPath, lastFileName, includeLastFile, PaginationSize) |
|||
if err != nil { |
|||
glog.Errorf("list folder %s: %v", entry.FullPath, err) |
|||
return nil, fmt.Errorf("list folder %s: %v", entry.FullPath, err) |
|||
} |
|||
if lastFileName == "" && !isRecursive && len(entries) > 0 { |
|||
// only for first iteration in the loop
|
|||
return nil, fmt.Errorf("fail to delete non-empty folder: %s", entry.FullPath) |
|||
} |
|||
|
|||
for _, sub := range entries { |
|||
lastFileName = sub.Name() |
|||
var dirChunks []*filer_pb.FileChunk |
|||
if sub.IsDirectory() { |
|||
dirChunks, err = f.doBatchDeleteFolderMetaAndData(ctx, sub, isRecursive, ignoreRecursiveError, shouldDeleteChunks) |
|||
} |
|||
if err != nil && !ignoreRecursiveError { |
|||
return nil, err |
|||
} |
|||
if shouldDeleteChunks { |
|||
chunks = append(chunks, dirChunks...) |
|||
} |
|||
} |
|||
|
|||
if len(entries) < PaginationSize { |
|||
break |
|||
} |
|||
} |
|||
|
|||
f.cacheDelDirectory(string(entry.FullPath)) |
|||
|
|||
glog.V(3).Infof("deleting directory %v", entry.FullPath) |
|||
|
|||
if storeDeletionErr := f.store.DeleteFolderChildren(ctx, entry.FullPath); storeDeletionErr != nil { |
|||
return nil, fmt.Errorf("filer store delete: %v", storeDeletionErr) |
|||
} |
|||
f.NotifyUpdateEvent(entry, nil, shouldDeleteChunks) |
|||
|
|||
return chunks, nil |
|||
} |
|||
|
|||
func (f *Filer) doDeleteEntryMetaAndData(ctx context.Context, entry *Entry, shouldDeleteChunks bool) (err error) { |
|||
|
|||
glog.V(3).Infof("deleting entry %v", entry.FullPath) |
|||
|
|||
if storeDeletionErr := f.store.DeleteEntry(ctx, entry.FullPath); storeDeletionErr != nil { |
|||
return fmt.Errorf("filer store delete: %v", storeDeletionErr) |
|||
} |
|||
f.NotifyUpdateEvent(entry, nil, shouldDeleteChunks) |
|||
|
|||
return nil |
|||
} |
@ -1,132 +0,0 @@ |
|||
package memdb |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"github.com/chrislusf/seaweedfs/weed/filer2" |
|||
"github.com/chrislusf/seaweedfs/weed/util" |
|||
"github.com/google/btree" |
|||
"strings" |
|||
"sync" |
|||
) |
|||
|
|||
func init() { |
|||
filer2.Stores = append(filer2.Stores, &MemDbStore{}) |
|||
} |
|||
|
|||
type MemDbStore struct { |
|||
tree *btree.BTree |
|||
treeLock sync.Mutex |
|||
} |
|||
|
|||
type entryItem struct { |
|||
*filer2.Entry |
|||
} |
|||
|
|||
func (a entryItem) Less(b btree.Item) bool { |
|||
return strings.Compare(string(a.FullPath), string(b.(entryItem).FullPath)) < 0 |
|||
} |
|||
|
|||
func (store *MemDbStore) GetName() string { |
|||
return "memory" |
|||
} |
|||
|
|||
func (store *MemDbStore) Initialize(configuration util.Configuration) (err error) { |
|||
store.tree = btree.New(8) |
|||
return nil |
|||
} |
|||
|
|||
func (store *MemDbStore) BeginTransaction(ctx context.Context) (context.Context, error) { |
|||
return ctx, nil |
|||
} |
|||
func (store *MemDbStore) CommitTransaction(ctx context.Context) error { |
|||
return nil |
|||
} |
|||
func (store *MemDbStore) RollbackTransaction(ctx context.Context) error { |
|||
return nil |
|||
} |
|||
|
|||
func (store *MemDbStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
// println("inserting", entry.FullPath)
|
|||
store.treeLock.Lock() |
|||
store.tree.ReplaceOrInsert(entryItem{entry}) |
|||
store.treeLock.Unlock() |
|||
return nil |
|||
} |
|||
|
|||
func (store *MemDbStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
if _, err = store.FindEntry(ctx, entry.FullPath); err != nil { |
|||
return fmt.Errorf("no such file %s : %v", entry.FullPath, err) |
|||
} |
|||
store.treeLock.Lock() |
|||
store.tree.ReplaceOrInsert(entryItem{entry}) |
|||
store.treeLock.Unlock() |
|||
return nil |
|||
} |
|||
|
|||
func (store *MemDbStore) FindEntry(ctx context.Context, fullpath filer2.FullPath) (entry *filer2.Entry, err error) { |
|||
item := store.tree.Get(entryItem{&filer2.Entry{FullPath: fullpath}}) |
|||
if item == nil { |
|||
return nil, filer2.ErrNotFound |
|||
} |
|||
entry = item.(entryItem).Entry |
|||
return entry, nil |
|||
} |
|||
|
|||
func (store *MemDbStore) DeleteEntry(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
store.treeLock.Lock() |
|||
store.tree.Delete(entryItem{&filer2.Entry{FullPath: fullpath}}) |
|||
store.treeLock.Unlock() |
|||
return nil |
|||
} |
|||
|
|||
func (store *MemDbStore) ListDirectoryEntries(ctx context.Context, fullpath filer2.FullPath, startFileName string, inclusive bool, limit int) (entries []*filer2.Entry, err error) { |
|||
|
|||
startFrom := string(fullpath) |
|||
if startFileName != "" { |
|||
startFrom = startFrom + "/" + startFileName |
|||
} |
|||
|
|||
store.tree.AscendGreaterOrEqual(entryItem{&filer2.Entry{FullPath: filer2.FullPath(startFrom)}}, |
|||
func(item btree.Item) bool { |
|||
if limit <= 0 { |
|||
return false |
|||
} |
|||
entry := item.(entryItem).Entry |
|||
// println("checking", entry.FullPath)
|
|||
|
|||
if entry.FullPath == fullpath { |
|||
// skipping the current directory
|
|||
// println("skipping the folder", entry.FullPath)
|
|||
return true |
|||
} |
|||
|
|||
dir, name := entry.FullPath.DirAndName() |
|||
if name == startFileName { |
|||
if inclusive { |
|||
limit-- |
|||
entries = append(entries, entry) |
|||
} |
|||
return true |
|||
} |
|||
|
|||
// only iterate the same prefix
|
|||
if !strings.HasPrefix(string(entry.FullPath), string(fullpath)) { |
|||
// println("breaking from", entry.FullPath)
|
|||
return false |
|||
} |
|||
|
|||
if dir != string(fullpath) { |
|||
// this could be items in deeper directories
|
|||
// println("skipping deeper folder", entry.FullPath)
|
|||
return true |
|||
} |
|||
// now process the directory items
|
|||
// println("adding entry", entry.FullPath)
|
|||
limit-- |
|||
entries = append(entries, entry) |
|||
return true |
|||
}, |
|||
) |
|||
return entries, nil |
|||
} |
@ -1,149 +0,0 @@ |
|||
package memdb |
|||
|
|||
import ( |
|||
"context" |
|||
"github.com/chrislusf/seaweedfs/weed/filer2" |
|||
"testing" |
|||
) |
|||
|
|||
func TestCreateAndFind(t *testing.T) { |
|||
filer := filer2.NewFiler(nil, nil) |
|||
store := &MemDbStore{} |
|||
store.Initialize(nil) |
|||
filer.SetStore(store) |
|||
filer.DisableDirectoryCache() |
|||
|
|||
ctx := context.Background() |
|||
|
|||
fullpath := filer2.FullPath("/home/chris/this/is/one/file1.jpg") |
|||
|
|||
entry1 := &filer2.Entry{ |
|||
FullPath: fullpath, |
|||
Attr: filer2.Attr{ |
|||
Mode: 0440, |
|||
Uid: 1234, |
|||
Gid: 5678, |
|||
}, |
|||
} |
|||
|
|||
if err := filer.CreateEntry(ctx, entry1); err != nil { |
|||
t.Errorf("create entry %v: %v", entry1.FullPath, err) |
|||
return |
|||
} |
|||
|
|||
entry, err := filer.FindEntry(ctx, fullpath) |
|||
|
|||
if err != nil { |
|||
t.Errorf("find entry: %v", err) |
|||
return |
|||
} |
|||
|
|||
if entry.FullPath != entry1.FullPath { |
|||
t.Errorf("find wrong entry: %v", entry.FullPath) |
|||
return |
|||
} |
|||
|
|||
} |
|||
|
|||
func TestCreateFileAndList(t *testing.T) { |
|||
filer := filer2.NewFiler(nil, nil) |
|||
store := &MemDbStore{} |
|||
store.Initialize(nil) |
|||
filer.SetStore(store) |
|||
filer.DisableDirectoryCache() |
|||
|
|||
ctx := context.Background() |
|||
|
|||
entry1 := &filer2.Entry{ |
|||
FullPath: filer2.FullPath("/home/chris/this/is/one/file1.jpg"), |
|||
Attr: filer2.Attr{ |
|||
Mode: 0440, |
|||
Uid: 1234, |
|||
Gid: 5678, |
|||
}, |
|||
} |
|||
|
|||
entry2 := &filer2.Entry{ |
|||
FullPath: filer2.FullPath("/home/chris/this/is/one/file2.jpg"), |
|||
Attr: filer2.Attr{ |
|||
Mode: 0440, |
|||
Uid: 1234, |
|||
Gid: 5678, |
|||
}, |
|||
} |
|||
|
|||
filer.CreateEntry(ctx, entry1) |
|||
filer.CreateEntry(ctx, entry2) |
|||
|
|||
// checking the 2 files
|
|||
entries, err := filer.ListDirectoryEntries(ctx, filer2.FullPath("/home/chris/this/is/one/"), "", false, 100) |
|||
|
|||
if err != nil { |
|||
t.Errorf("list entries: %v", err) |
|||
return |
|||
} |
|||
|
|||
if len(entries) != 2 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
if entries[0].FullPath != entry1.FullPath { |
|||
t.Errorf("find wrong entry 1: %v", entries[0].FullPath) |
|||
return |
|||
} |
|||
|
|||
if entries[1].FullPath != entry2.FullPath { |
|||
t.Errorf("find wrong entry 2: %v", entries[1].FullPath) |
|||
return |
|||
} |
|||
|
|||
// checking the offset
|
|||
entries, err = filer.ListDirectoryEntries(ctx, filer2.FullPath("/home/chris/this/is/one/"), "file1.jpg", false, 100) |
|||
if len(entries) != 1 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
// checking one upper directory
|
|||
entries, _ = filer.ListDirectoryEntries(ctx, filer2.FullPath("/home/chris/this/is"), "", false, 100) |
|||
if len(entries) != 1 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
// checking root directory
|
|||
entries, _ = filer.ListDirectoryEntries(ctx, filer2.FullPath("/"), "", false, 100) |
|||
if len(entries) != 1 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
// add file3
|
|||
file3Path := filer2.FullPath("/home/chris/this/is/file3.jpg") |
|||
entry3 := &filer2.Entry{ |
|||
FullPath: file3Path, |
|||
Attr: filer2.Attr{ |
|||
Mode: 0440, |
|||
Uid: 1234, |
|||
Gid: 5678, |
|||
}, |
|||
} |
|||
filer.CreateEntry(ctx, entry3) |
|||
|
|||
// checking one upper directory
|
|||
entries, _ = filer.ListDirectoryEntries(ctx, filer2.FullPath("/home/chris/this/is"), "", false, 100) |
|||
if len(entries) != 2 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
// delete file and count
|
|||
filer.DeleteEntryMetaAndData(ctx, file3Path, false, false) |
|||
entries, _ = filer.ListDirectoryEntries(ctx, filer2.FullPath("/home/chris/this/is"), "", false, 100) |
|||
if len(entries) != 1 { |
|||
t.Errorf("list entries count: %v", len(entries)) |
|||
return |
|||
} |
|||
|
|||
} |
@ -0,0 +1,251 @@ |
|||
// +build !386
|
|||
// +build !arm
|
|||
|
|||
package tikv |
|||
|
|||
import ( |
|||
"bytes" |
|||
"context" |
|||
"crypto/md5" |
|||
"fmt" |
|||
"io" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/filer2" |
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
weed_util "github.com/chrislusf/seaweedfs/weed/util" |
|||
|
|||
"github.com/pingcap/tidb/kv" |
|||
"github.com/pingcap/tidb/store/tikv" |
|||
) |
|||
|
|||
func init() { |
|||
filer2.Stores = append(filer2.Stores, &TikvStore{}) |
|||
} |
|||
|
|||
type TikvStore struct { |
|||
store kv.Storage |
|||
} |
|||
|
|||
func (store *TikvStore) GetName() string { |
|||
return "tikv" |
|||
} |
|||
|
|||
func (store *TikvStore) Initialize(configuration weed_util.Configuration) (err error) { |
|||
pdAddr := configuration.GetString("pdAddress") |
|||
return store.initialize(pdAddr) |
|||
} |
|||
|
|||
func (store *TikvStore) initialize(pdAddr string) (err error) { |
|||
glog.Infof("filer store tikv pd address: %s", pdAddr) |
|||
|
|||
driver := tikv.Driver{} |
|||
|
|||
store.store, err = driver.Open(fmt.Sprintf("tikv://%s", pdAddr)) |
|||
|
|||
if err != nil { |
|||
return fmt.Errorf("open tikv %s : %v", pdAddr, err) |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
func (store *TikvStore) BeginTransaction(ctx context.Context) (context.Context, error) { |
|||
tx, err := store.store.Begin() |
|||
if err != nil { |
|||
return ctx, err |
|||
} |
|||
return context.WithValue(ctx, "tx", tx), nil |
|||
} |
|||
func (store *TikvStore) CommitTransaction(ctx context.Context) error { |
|||
tx, ok := ctx.Value("tx").(kv.Transaction) |
|||
if ok { |
|||
return tx.Commit(ctx) |
|||
} |
|||
return nil |
|||
} |
|||
func (store *TikvStore) RollbackTransaction(ctx context.Context) error { |
|||
tx, ok := ctx.Value("tx").(kv.Transaction) |
|||
if ok { |
|||
return tx.Rollback() |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (store *TikvStore) getTx(ctx context.Context) kv.Transaction { |
|||
if tx, ok := ctx.Value("tx").(kv.Transaction); ok { |
|||
return tx |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (store *TikvStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
dir, name := entry.DirAndName() |
|||
key := genKey(dir, name) |
|||
|
|||
value, err := entry.EncodeAttributesAndChunks() |
|||
if err != nil { |
|||
return fmt.Errorf("encoding %s %+v: %v", entry.FullPath, entry.Attr, err) |
|||
} |
|||
|
|||
err = store.getTx(ctx).Set(key, value) |
|||
|
|||
if err != nil { |
|||
return fmt.Errorf("persisting %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
// println("saved", entry.FullPath, "chunks", len(entry.Chunks))
|
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *TikvStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
|
|||
return store.InsertEntry(ctx, entry) |
|||
} |
|||
|
|||
func (store *TikvStore) FindEntry(ctx context.Context, fullpath filer2.FullPath) (entry *filer2.Entry, err error) { |
|||
dir, name := fullpath.DirAndName() |
|||
key := genKey(dir, name) |
|||
|
|||
data, err := store.getTx(ctx).Get(ctx, key) |
|||
|
|||
if err == kv.ErrNotExist { |
|||
return nil, filer2.ErrNotFound |
|||
} |
|||
if err != nil { |
|||
return nil, fmt.Errorf("get %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
entry = &filer2.Entry{ |
|||
FullPath: fullpath, |
|||
} |
|||
err = entry.DecodeAttributesAndChunks(data) |
|||
if err != nil { |
|||
return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err) |
|||
} |
|||
|
|||
// println("read", entry.FullPath, "chunks", len(entry.Chunks), "data", len(data), string(data))
|
|||
|
|||
return entry, nil |
|||
} |
|||
|
|||
func (store *TikvStore) DeleteEntry(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
dir, name := fullpath.DirAndName() |
|||
key := genKey(dir, name) |
|||
|
|||
err = store.getTx(ctx).Delete(key) |
|||
if err != nil { |
|||
return fmt.Errorf("delete %s : %v", fullpath, err) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *TikvStore) DeleteFolderChildren(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
|
|||
directoryPrefix := genDirectoryKeyPrefix(fullpath, "") |
|||
|
|||
tx := store.getTx(ctx) |
|||
|
|||
iter, err := tx.Iter(directoryPrefix, nil) |
|||
if err != nil { |
|||
return fmt.Errorf("deleteFolderChildren %s: %v", fullpath, err) |
|||
} |
|||
defer iter.Close() |
|||
for iter.Valid() { |
|||
key := iter.Key() |
|||
if !bytes.HasPrefix(key, directoryPrefix) { |
|||
break |
|||
} |
|||
fileName := getNameFromKey(key) |
|||
if fileName == "" { |
|||
iter.Next() |
|||
continue |
|||
} |
|||
|
|||
if err = tx.Delete(genKey(string(fullpath), fileName)); err != nil { |
|||
return fmt.Errorf("delete %s : %v", fullpath, err) |
|||
} |
|||
|
|||
iter.Next() |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (store *TikvStore) ListDirectoryEntries(ctx context.Context, fullpath filer2.FullPath, startFileName string, inclusive bool, |
|||
limit int) (entries []*filer2.Entry, err error) { |
|||
|
|||
directoryPrefix := genDirectoryKeyPrefix(fullpath, "") |
|||
lastFileStart := genDirectoryKeyPrefix(fullpath, startFileName) |
|||
|
|||
iter, err := store.getTx(ctx).Iter(lastFileStart, nil) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("list %s: %v", fullpath, err) |
|||
} |
|||
defer iter.Close() |
|||
for iter.Valid() { |
|||
key := iter.Key() |
|||
if !bytes.HasPrefix(key, directoryPrefix) { |
|||
break |
|||
} |
|||
fileName := getNameFromKey(key) |
|||
if fileName == "" { |
|||
iter.Next() |
|||
continue |
|||
} |
|||
if fileName == startFileName && !inclusive { |
|||
iter.Next() |
|||
continue |
|||
} |
|||
limit-- |
|||
if limit < 0 { |
|||
break |
|||
} |
|||
entry := &filer2.Entry{ |
|||
FullPath: filer2.NewFullPath(string(fullpath), fileName), |
|||
} |
|||
|
|||
// println("list", entry.FullPath, "chunks", len(entry.Chunks))
|
|||
|
|||
if decodeErr := entry.DecodeAttributesAndChunks(iter.Value()); decodeErr != nil { |
|||
err = decodeErr |
|||
glog.V(0).Infof("list %s : %v", entry.FullPath, err) |
|||
break |
|||
} |
|||
entries = append(entries, entry) |
|||
iter.Next() |
|||
} |
|||
|
|||
return entries, err |
|||
} |
|||
|
|||
func genKey(dirPath, fileName string) (key []byte) { |
|||
key = hashToBytes(dirPath) |
|||
key = append(key, []byte(fileName)...) |
|||
return key |
|||
} |
|||
|
|||
func genDirectoryKeyPrefix(fullpath filer2.FullPath, startFileName string) (keyPrefix []byte) { |
|||
keyPrefix = hashToBytes(string(fullpath)) |
|||
if len(startFileName) > 0 { |
|||
keyPrefix = append(keyPrefix, []byte(startFileName)...) |
|||
} |
|||
return keyPrefix |
|||
} |
|||
|
|||
func getNameFromKey(key []byte) string { |
|||
|
|||
return string(key[md5.Size:]) |
|||
|
|||
} |
|||
|
|||
// hash directory
|
|||
func hashToBytes(dir string) []byte { |
|||
h := md5.New() |
|||
io.WriteString(h, dir) |
|||
|
|||
b := h.Sum(nil) |
|||
|
|||
return b |
|||
} |
@ -0,0 +1,65 @@ |
|||
// +build 386 arm
|
|||
|
|||
package tikv |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/filer2" |
|||
weed_util "github.com/chrislusf/seaweedfs/weed/util" |
|||
) |
|||
|
|||
func init() { |
|||
filer2.Stores = append(filer2.Stores, &TikvStore{}) |
|||
} |
|||
|
|||
type TikvStore struct { |
|||
} |
|||
|
|||
func (store *TikvStore) GetName() string { |
|||
return "tikv" |
|||
} |
|||
|
|||
func (store *TikvStore) Initialize(configuration weed_util.Configuration) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) initialize(pdAddr string) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) BeginTransaction(ctx context.Context) (context.Context, error) { |
|||
return nil, fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
func (store *TikvStore) CommitTransaction(ctx context.Context) error { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
func (store *TikvStore) RollbackTransaction(ctx context.Context) error { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) FindEntry(ctx context.Context, fullpath filer2.FullPath) (entry *filer2.Entry, err error) { |
|||
return nil, fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) DeleteEntry(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) DeleteFolderChildren(ctx context.Context, fullpath filer2.FullPath) (err error) { |
|||
return fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
|||
|
|||
func (store *TikvStore) ListDirectoryEntries(ctx context.Context, fullpath filer2.FullPath, startFileName string, inclusive bool, |
|||
limit int) (entries []*filer2.Entry, err error) { |
|||
return nil, fmt.Errorf("not implemented for 32 bit computers") |
|||
} |
@ -0,0 +1,142 @@ |
|||
package filesys |
|||
|
|||
import ( |
|||
"context" |
|||
"path/filepath" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb" |
|||
"github.com/seaweedfs/fuse" |
|||
) |
|||
|
|||
func getxattr(entry *filer_pb.Entry, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { |
|||
|
|||
if entry == nil { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
if entry.Extended == nil { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
data, found := entry.Extended[req.Name] |
|||
if !found { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
if req.Position < uint32(len(data)) { |
|||
size := req.Size |
|||
if req.Position+size >= uint32(len(data)) { |
|||
size = uint32(len(data)) - req.Position |
|||
} |
|||
if size == 0 { |
|||
resp.Xattr = data[req.Position:] |
|||
} else { |
|||
resp.Xattr = data[req.Position : req.Position+size] |
|||
} |
|||
} |
|||
|
|||
return nil |
|||
|
|||
} |
|||
|
|||
func setxattr(entry *filer_pb.Entry, req *fuse.SetxattrRequest) error { |
|||
|
|||
if entry == nil { |
|||
return fuse.EIO |
|||
} |
|||
|
|||
if entry.Extended == nil { |
|||
entry.Extended = make(map[string][]byte) |
|||
} |
|||
data, _ := entry.Extended[req.Name] |
|||
|
|||
newData := make([]byte, int(req.Position)+len(req.Xattr)) |
|||
|
|||
copy(newData, data) |
|||
|
|||
copy(newData[int(req.Position):], req.Xattr) |
|||
|
|||
entry.Extended[req.Name] = newData |
|||
|
|||
return nil |
|||
|
|||
} |
|||
|
|||
func removexattr(entry *filer_pb.Entry, req *fuse.RemovexattrRequest) error { |
|||
|
|||
if entry == nil { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
|
|||
if entry.Extended == nil { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
|
|||
_, found := entry.Extended[req.Name] |
|||
|
|||
if !found { |
|||
return fuse.ErrNoXattr |
|||
} |
|||
|
|||
delete(entry.Extended, req.Name) |
|||
|
|||
return nil |
|||
|
|||
} |
|||
|
|||
func listxattr(entry *filer_pb.Entry, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { |
|||
|
|||
if entry == nil { |
|||
return fuse.EIO |
|||
} |
|||
|
|||
for k := range entry.Extended { |
|||
resp.Append(k) |
|||
} |
|||
|
|||
size := req.Size |
|||
if req.Position+size >= uint32(len(resp.Xattr)) { |
|||
size = uint32(len(resp.Xattr)) - req.Position |
|||
} |
|||
|
|||
if size == 0 { |
|||
resp.Xattr = resp.Xattr[req.Position:] |
|||
} else { |
|||
resp.Xattr = resp.Xattr[req.Position : req.Position+size] |
|||
} |
|||
|
|||
return nil |
|||
|
|||
} |
|||
|
|||
func (wfs *WFS) maybeLoadEntry(ctx context.Context, dir, name string) (entry *filer_pb.Entry, err error) { |
|||
|
|||
fullpath := filepath.Join(dir, name) |
|||
item := wfs.listDirectoryEntriesCache.Get(fullpath) |
|||
if item != nil && !item.Expired() { |
|||
entry = item.Value().(*filer_pb.Entry) |
|||
return |
|||
} |
|||
glog.V(3).Infof("read entry cache miss %s", fullpath) |
|||
|
|||
err = wfs.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error { |
|||
|
|||
request := &filer_pb.LookupDirectoryEntryRequest{ |
|||
Name: name, |
|||
Directory: dir, |
|||
} |
|||
|
|||
resp, err := client.LookupDirectoryEntry(ctx, request) |
|||
if err != nil { |
|||
glog.V(3).Infof("file attr read file %v: %v", request, err) |
|||
return fuse.ENOENT |
|||
} |
|||
|
|||
entry = resp.Entry |
|||
if entry != nil { |
|||
wfs.listDirectoryEntriesCache.Set(fullpath, entry, wfs.option.EntryCacheTtl) |
|||
} |
|||
|
|||
return nil |
|||
}) |
|||
|
|||
return |
|||
} |
@ -1,117 +0,0 @@ |
|||
package: github.com/chrislusf/seaweedfs/weed |
|||
import: |
|||
- package: cloud.google.com/go |
|||
version: ^0.40.0 |
|||
subpackages: |
|||
- pubsub |
|||
- storage |
|||
- package: github.com/Azure/azure-storage-blob-go |
|||
version: ^0.7.0 |
|||
subpackages: |
|||
- azblob |
|||
- package: github.com/Shopify/sarama |
|||
version: ^1.22.1 |
|||
- package: github.com/aws/aws-sdk-go |
|||
version: ^1.20.12 |
|||
subpackages: |
|||
- aws |
|||
- aws/awserr |
|||
- aws/credentials |
|||
- aws/session |
|||
- service/s3 |
|||
- service/s3/s3iface |
|||
- service/sqs |
|||
- package: github.com/chrislusf/raft |
|||
subpackages: |
|||
- protobuf |
|||
- package: github.com/dgrijalva/jwt-go |
|||
version: ^3.2.0 |
|||
- package: github.com/disintegration/imaging |
|||
version: ^1.6.0 |
|||
- package: github.com/dustin/go-humanize |
|||
version: ^1.0.0 |
|||
- package: github.com/gabriel-vasile/mimetype |
|||
version: ^0.3.14 |
|||
- package: github.com/go-redis/redis |
|||
version: ^6.15.3 |
|||
- package: github.com/go-sql-driver/mysql |
|||
version: ^1.4.1 |
|||
- package: github.com/gocql/gocql |
|||
- package: github.com/golang/protobuf |
|||
version: ^1.3.1 |
|||
subpackages: |
|||
- proto |
|||
- package: github.com/google/btree |
|||
version: ^1.0.0 |
|||
- package: github.com/gorilla/mux |
|||
version: ^1.7.3 |
|||
- package: github.com/jacobsa/daemonize |
|||
- package: github.com/kardianos/osext |
|||
- package: github.com/karlseguin/ccache |
|||
version: ^2.0.3 |
|||
- package: github.com/klauspost/crc32 |
|||
version: ^1.2.0 |
|||
- package: github.com/klauspost/reedsolomon |
|||
version: ^1.9.2 |
|||
- package: github.com/kurin/blazer |
|||
version: ^0.5.3 |
|||
subpackages: |
|||
- b2 |
|||
- package: github.com/lib/pq |
|||
version: ^1.1.1 |
|||
- package: github.com/peterh/liner |
|||
version: ^1.1.0 |
|||
- package: github.com/prometheus/client_golang |
|||
version: ^1.0.0 |
|||
subpackages: |
|||
- prometheus |
|||
- prometheus/push |
|||
- package: github.com/rakyll/statik |
|||
version: ^0.1.6 |
|||
subpackages: |
|||
- fs |
|||
- package: github.com/rwcarlsen/goexif |
|||
subpackages: |
|||
- exif |
|||
- package: github.com/satori/go.uuid |
|||
version: ^1.2.0 |
|||
- package: github.com/seaweedfs/fuse |
|||
subpackages: |
|||
- fs |
|||
- package: github.com/spf13/viper |
|||
version: ^1.4.0 |
|||
- package: github.com/syndtr/goleveldb |
|||
version: ^1.0.0 |
|||
subpackages: |
|||
- leveldb |
|||
- leveldb/opt |
|||
- leveldb/util |
|||
- package: github.com/willf/bloom |
|||
version: ^2.0.3 |
|||
- package: gocloud.dev |
|||
version: ^0.15.0 |
|||
subpackages: |
|||
- pubsub |
|||
- pubsub/awssnssqs |
|||
- pubsub/azuresb |
|||
- pubsub/gcppubsub |
|||
- pubsub/natspubsub |
|||
- pubsub/rabbitpubsub |
|||
- package: golang.org/x/net |
|||
subpackages: |
|||
- context |
|||
- webdav |
|||
- package: golang.org/x/tools |
|||
subpackages: |
|||
- godoc/util |
|||
- package: google.golang.org/api |
|||
version: ^0.7.0 |
|||
subpackages: |
|||
- option |
|||
- package: google.golang.org/grpc |
|||
version: ^1.21.1 |
|||
subpackages: |
|||
- credentials |
|||
- keepalive |
|||
- peer |
|||
- reflection |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue