Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
26eea2bd
Unverified
Commit
26eea2bd
authored
Apr 13, 2020
by
Zahoor Mohamed
Committed by
GitHub
Apr 13, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add localstore from swarm to bee (#82)
parent
0b2d9e34
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
7173 additions
and
132 deletions
+7173
-132
Makefile
Makefile
+2
-2
go.mod
go.mod
+1
-0
go.sum
go.sum
+48
-130
doc.go
pkg/storage/localstore/doc.go
+56
-0
export.go
pkg/storage/localstore/export.go
+206
-0
export_test.go
pkg/storage/localstore/export_test.go
+80
-0
gc.go
pkg/storage/localstore/gc.go
+285
-0
gc_test.go
pkg/storage/localstore/gc_test.go
+531
-0
index_test.go
pkg/storage/localstore/index_test.go
+216
-0
localstore.go
pkg/storage/localstore/localstore.go
+548
-0
localstore_test.go
pkg/storage/localstore/localstore_test.go
+579
-0
migration.go
pkg/storage/localstore/migration.go
+185
-0
migration_test.go
pkg/storage/localstore/migration_test.go
+378
-0
mode_get.go
pkg/storage/localstore/mode_get.go
+172
-0
mode_get_multi.go
pkg/storage/localstore/mode_get_multi.go
+91
-0
mode_get_multi_test.go
pkg/storage/localstore/mode_get_multi_test.go
+82
-0
mode_get_test.go
pkg/storage/localstore/mode_get_test.go
+278
-0
mode_has.go
pkg/storage/localstore/mode_has.go
+54
-0
mode_has_test.go
pkg/storage/localstore/mode_has_test.go
+94
-0
mode_put.go
pkg/storage/localstore/mode_put.go
+376
-0
mode_put_test.go
pkg/storage/localstore/mode_put_test.go
+574
-0
mode_set.go
pkg/storage/localstore/mode_set.go
+449
-0
mode_set_test.go
pkg/storage/localstore/mode_set_test.go
+365
-0
retrieval_index_test.go
pkg/storage/localstore/retrieval_index_test.go
+147
-0
schema.go
pkg/storage/localstore/schema.go
+71
-0
subscription_pull.go
pkg/storage/localstore/subscription_pull.go
+227
-0
subscription_pull_test.go
pkg/storage/localstore/subscription_pull_test.go
+688
-0
subscription_push.go
pkg/storage/localstore/subscription_push.go
+163
-0
subscription_push_test.go
pkg/storage/localstore/subscription_push_test.go
+206
-0
000002.log
pkg/storage/localstore/testdata/sanctuary/000002.log
+0
-0
CURRENT
pkg/storage/localstore/testdata/sanctuary/CURRENT
+1
-0
CURRENT.bak
pkg/storage/localstore/testdata/sanctuary/CURRENT.bak
+1
-0
LOCK
pkg/storage/localstore/testdata/sanctuary/LOCK
+0
-0
LOG
pkg/storage/localstore/testdata/sanctuary/LOG
+19
-0
MANIFEST-000003
pkg/storage/localstore/testdata/sanctuary/MANIFEST-000003
+0
-0
No files found.
Makefile
View file @
26eea2bd
...
@@ -10,7 +10,7 @@ endif
...
@@ -10,7 +10,7 @@ endif
all
:
build lint vet test binary
all
:
build lint vet test binary
.PHONY
:
binary
.PHONY
:
binary
binary
:
export CGO_ENABLED=
0
binary
:
export CGO_ENABLED=
1
#
set to 0 when go-ethereum/metrics dependecy is removed
binary
:
dist FORCE
binary
:
dist FORCE
$(GO)
version
$(GO)
version
$(GO)
build
-trimpath
-ldflags
"
$(LDFLAGS)
"
-o
dist/bee ./cmd/bee
$(GO)
build
-trimpath
-ldflags
"
$(LDFLAGS)
"
-o
dist/bee ./cmd/bee
...
@@ -31,7 +31,7 @@ test:
...
@@ -31,7 +31,7 @@ test:
$(GO)
test
-v
-race
./...
$(GO)
test
-v
-race
./...
.PHONY
:
build
.PHONY
:
build
build
:
export CGO_ENABLED=
0
build
:
export CGO_ENABLED=
1
#
set to 0 when go-ethereum/metrics dependecy is removed
build
:
build
:
$(GO)
build
-trimpath
-ldflags
"
$(LDFLAGS)
"
./...
$(GO)
build
-trimpath
-ldflags
"
$(LDFLAGS)
"
./...
...
...
go.mod
View file @
26eea2bd
...
@@ -6,6 +6,7 @@ require (
...
@@ -6,6 +6,7 @@ require (
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btcd v0.20.1-beta
github.com/coreos/go-semver v0.3.0
github.com/coreos/go-semver v0.3.0
github.com/dgraph-io/badger/v2 v2.0.3
github.com/dgraph-io/badger/v2 v2.0.3
github.com/ethereum/go-ethereum v1.9.2
github.com/ethersphere/swarm v0.5.7
github.com/ethersphere/swarm v0.5.7
github.com/gogo/protobuf v1.3.1
github.com/gogo/protobuf v1.3.1
github.com/gorilla/handlers v1.4.2
github.com/gorilla/handlers v1.4.2
...
...
go.sum
View file @
26eea2bd
...
@@ -12,49 +12,35 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv
...
@@ -12,49 +12,35 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/Azure/azure-pipeline-go v0.0.0-20180607212504-7571e8eb0876/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-pipeline-go v0.0.0-20180607212504-7571e8eb0876/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
github.com/Azure/azure-storage-blob-go v0.0.0-20180712005634-eaae161d9d5e/go.mod h1:x2mtS6O3mnMEZOJp7d7oldh8IvatBrMfReiyQ+cKgKY=
github.com/Azure/azure-storage-blob-go v0.0.0-20180712005634-eaae161d9d5e/go.mod h1:x2mtS6O3mnMEZOJp7d7oldh8IvatBrMfReiyQ+cKgKY=
github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
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/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75 h1:3ILjVyslFbc4jl1w5TWuvvslFD/nDfR2H8tVaMVLrEY=
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/allegro/bigcache v0.0.0-20190218064605-e24eb225f156 h1:hh7BAWFHv41r0gce0KRYtDJpL4erKfmB1/mpgoSADeI=
github.com/allegro/bigcache v0.0.0-20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v0.0.0-20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apilayer/freegeoip v0.0.0-20180702111401-3f942d1392f6/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
github.com/apilayer/freegeoip v0.0.0-20180702111401-3f942d1392f6/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
...
@@ -77,18 +63,16 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
...
@@ -77,18 +63,16 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v
0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s
=
github.com/cespare/cp v
1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU
=
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
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/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
...
@@ -105,10 +89,10 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
...
@@ -105,10 +89,10 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
...
@@ -132,56 +116,50 @@ github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUn
...
@@ -132,56 +116,50 @@ github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUn
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.7.3-0.20190806133308-ecdb0b22393b h1:9jRwTjp/M3uPTfYqgEo3Vpb4sVebFq5z1KPSaApNf2Y=
github.com/docker/docker v0.7.3-0.20190806133308-ecdb0b22393b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20190806133308-ecdb0b22393b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa h1:o8OuEkracbk3qH6GvlI6XpEN1HTSxkzOG42xZpfDv/s=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa h1:o8OuEkracbk3qH6GvlI6XpEN1HTSxkzOG42xZpfDv/s=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa h1:XKAhUk/dtp+CV0VO6mhG2V7jA9vbcGcnYF/Ay9NjZrY=
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.9.2 h1:RMIHDO/diqXEgORSVzYx8xW9x2+S32PoAX5lQwya0Lw=
github.com/ethereum/go-ethereum v1.9.2 h1:RMIHDO/diqXEgORSVzYx8xW9x2+S32PoAX5lQwya0Lw=
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
github.com/ethereum/go-ethereum v1.9.12 h1:EPtimwsp/KGDSiXcNunzsI4kefdsMHZGJntKx3fvbaI=
github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo=
github.com/ethersphere/go-sw3 v0.2.1/go.mod h1:HukT0aZ6QdW/d7zuD/0g5xlw6ewu9QeqHojxLDsaERQ=
github.com/ethersphere/go-sw3 v0.2.1/go.mod h1:HukT0aZ6QdW/d7zuD/0g5xlw6ewu9QeqHojxLDsaERQ=
github.com/ethersphere/swarm v0.5.7 h1:lD8oxKhFtU+t+sRwGEKuUFtqlxVvcpozRwReZDFn7Z8=
github.com/ethersphere/swarm v0.5.7 h1:lD8oxKhFtU+t+sRwGEKuUFtqlxVvcpozRwReZDFn7Z8=
github.com/ethersphere/swarm v0.5.7/go.mod h1:X5+3GAz6aWOHnBqA0xJccMFuCCJ18ni5UyTAi6XTNaQ=
github.com/ethersphere/swarm v0.5.7/go.mod h1:X5+3GAz6aWOHnBqA0xJccMFuCCJ18ni5UyTAi6XTNaQ=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gballet/go-libpcsclite v0.0.0-20190528105824-2fd9b619dd3c h1:gID5iWto0hEmbyMl+15Rkju0P+8uvF0jSn1cWdyv+5M=
github.com/gballet/go-libpcsclite v0.0.0-20190528105824-2fd9b619dd3c/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20190528105824-2fd9b619dd3c/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.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.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
...
@@ -193,16 +171,16 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
...
@@ -193,16 +171,16 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/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.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.
3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y
=
github.com/golang/mock v1.
4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg
=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/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.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/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-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
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/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
...
@@ -218,6 +196,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
...
@@ -218,6 +196,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
...
@@ -233,6 +212,7 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0
...
@@ -233,6 +212,7 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.0.0-20190624222214-25d8b0b66985/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.0.0-20190624222214-25d8b0b66985/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
...
@@ -241,13 +221,11 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
...
@@ -241,13 +221,11 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
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/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4=
github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
...
@@ -256,7 +234,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg
...
@@ -256,7 +234,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
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 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.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
...
@@ -277,7 +254,6 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
...
@@ -277,7 +254,6 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
...
@@ -286,19 +262,16 @@ github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj
...
@@ -286,19 +262,16 @@ github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj
github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU=
github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU=
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
...
@@ -317,11 +290,10 @@ github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQ
...
@@ -317,11 +290,10 @@ github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQ
github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
...
@@ -333,20 +305,19 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
...
@@ -333,20 +305,19 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.
1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w
=
github.com/julienschmidt/httprouter v1.
2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g
=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8uXRLnpdSb9noCEj+vHacjmhp68=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
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/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
...
@@ -359,11 +330,14 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
...
@@ -359,11 +330,14 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/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/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=
github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=
...
@@ -376,12 +350,9 @@ github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2h
...
@@ -376,12 +350,9 @@ github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2h
github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=
github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=
github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM=
github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM=
github.com/libp2p/go-libp2p v0.5.1 h1:kZ9jg+2B9IIptRcltBHKBrQdhXNNSrjCoztvrMx7tqI=
github.com/libp2p/go-libp2p v0.5.1/go.mod h1:Os7a5Z3B+ErF4v7zgIJ7nBHNu2LYt8ZMLkTQUB3G/wA=
github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
github.com/libp2p/go-libp2p v0.7.4 h1:xVj1oSlN0C+FlxqiLuHC8WruMvq24xxfeVxmNhTG0r0=
github.com/libp2p/go-libp2p v0.7.4 h1:xVj1oSlN0C+FlxqiLuHC8WruMvq24xxfeVxmNhTG0r0=
...
@@ -407,7 +378,6 @@ github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7O
...
@@ -407,7 +378,6 @@ github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7O
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
github.com/libp2p/go-libp2p-core v0.3.0 h1:F7PqduvrztDtFsAa/bcheQ3azmNo+Nq7m8hQY5GiUW8=
github.com/libp2p/go-libp2p-core v0.3.0 h1:F7PqduvrztDtFsAa/bcheQ3azmNo+Nq7m8hQY5GiUW8=
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=
...
@@ -434,12 +404,11 @@ github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6
...
@@ -434,12 +404,11 @@ github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
github.com/libp2p/go-libp2p-peerstore v0.1.4 h1:d23fvq5oYMJ/lkkbO4oTwBp/JP+I/1m5gZJobNXCE/k=
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
...
@@ -447,8 +416,6 @@ github.com/libp2p/go-libp2p-peerstore v0.2.3 h1:MofRq2l3c15vQpEygTetV+zRRrncz+kt
...
@@ -447,8 +416,6 @@ github.com/libp2p/go-libp2p-peerstore v0.2.3 h1:MofRq2l3c15vQpEygTetV+zRRrncz+kt
github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=
github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
github.com/libp2p/go-libp2p-quic-transport v0.2.2 h1:XyGRqFHD1oHdI2k98P1tWWRb9s27fl1SfmCcaX8plso=
github.com/libp2p/go-libp2p-quic-transport v0.2.2/go.mod h1:rVzcsiuOFBomAqvNOxeBUcP4vM4wE+NqqRZWvxjkbe0=
github.com/libp2p/go-libp2p-quic-transport v0.3.3 h1:A920y1nion8PkGKsEnMiho+3OHpXUqfy35YnPfta4aI=
github.com/libp2p/go-libp2p-quic-transport v0.3.3 h1:A920y1nion8PkGKsEnMiho+3OHpXUqfy35YnPfta4aI=
github.com/libp2p/go-libp2p-quic-transport v0.3.3/go.mod h1:DqzycUAZfeuritygmSOh3kPrs/Cqvc0V1uGkoCEGUXI=
github.com/libp2p/go-libp2p-quic-transport v0.3.3/go.mod h1:DqzycUAZfeuritygmSOh3kPrs/Cqvc0V1uGkoCEGUXI=
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
...
@@ -468,8 +435,6 @@ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MB
...
@@ -468,8 +435,6 @@ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MB
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU=
github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU=
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-tls v0.1.1 h1:tjW7njTM8JX8FbEvqr8/VSKBdZYZ7CtGtv3i6NiFf10=
github.com/libp2p/go-libp2p-tls v0.1.1/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw=
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw=
...
@@ -477,8 +442,6 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07q
...
@@ -477,8 +442,6 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07q
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk=
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk=
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI=
github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI=
github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
github.com/libp2p/go-libp2p-yamux v0.2.7 h1:vzKu0NVtxvEIDGCv6mjKRcK0gipSgaXmJZ6jFv0d/dk=
github.com/libp2p/go-libp2p-yamux v0.2.7 h1:vzKu0NVtxvEIDGCv6mjKRcK0gipSgaXmJZ6jFv0d/dk=
...
@@ -512,6 +475,7 @@ github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0
...
@@ -512,6 +475,7 @@ github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0
github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M=
github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M=
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
github.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q=
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg=
github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg=
...
@@ -527,15 +491,10 @@ github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzl
...
@@ -527,15 +491,10 @@ github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzl
github.com/libp2p/go-ws-transport v0.3.0 h1:mjo6pL5aVR9rCjl9wNq3DupbaQlyR61pzoOT2MdtxaA=
github.com/libp2p/go-ws-transport v0.3.0 h1:mjo6pL5aVR9rCjl9wNq3DupbaQlyR61pzoOT2MdtxaA=
github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI=
github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.5 h1:ibuz4naPAully0pN6J/kmUARiqLpnDQIzI/8GCOrljg=
github.com/libp2p/go-yamux v1.3.5 h1:ibuz4naPAully0pN6J/kmUARiqLpnDQIzI/8GCOrljg=
github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
github.com/lucas-clemente/quic-go v0.14.1 h1:c1aKoBZKOPA+49q96B1wGkibyPP0AxYh45WuAoq+87E=
github.com/lucas-clemente/quic-go v0.14.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
github.com/lucas-clemente/quic-go v0.15.2/go.mod h1:qxmO5Y4ZMhdNkunGfxuZnZXnJwYpW9vjQkyrZ7BsgUI=
github.com/lucas-clemente/quic-go v0.15.2/go.mod h1:qxmO5Y4ZMhdNkunGfxuZnZXnJwYpW9vjQkyrZ7BsgUI=
github.com/lucas-clemente/quic-go v0.15.3 h1:i6n4Jr7673z9TlurAjc87+GlE/BN10++r9XZIPS9j6I=
github.com/lucas-clemente/quic-go v0.15.3 h1:i6n4Jr7673z9TlurAjc87+GlE/BN10++r9XZIPS9j6I=
github.com/lucas-clemente/quic-go v0.15.3/go.mod h1:oj40DjNLuNugvtXWg4PwaYgv7tAbzAabrT57CC69EhI=
github.com/lucas-clemente/quic-go v0.15.3/go.mod h1:oj40DjNLuNugvtXWg4PwaYgv7tAbzAabrT57CC69EhI=
...
@@ -545,31 +504,23 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
...
@@ -545,31 +504,23 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/chacha20 v0.2.0 h1:f40vqzzx+3GdOmzQoItkLX5WLvHgPgyYqFFIO5Gh4hQ=
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gtbkks=
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
github.com/marten-seemann/qtls v0.8.0/go.mod h1:Lao6jDqlCfxyLKYFmZXGm2LSHBgVn+P+ROOex6YkT+k=
github.com/marten-seemann/qtls v0.8.0/go.mod h1:Lao6jDqlCfxyLKYFmZXGm2LSHBgVn+P+ROOex6YkT+k=
github.com/marten-seemann/qtls v0.9.0 h1:8Zguhc72eS+DH5EAb0BpAPIy3HDXYcihQi4xoDZOnjQ=
github.com/marten-seemann/qtls v0.9.0 h1:8Zguhc72eS+DH5EAb0BpAPIy3HDXYcihQi4xoDZOnjQ=
github.com/marten-seemann/qtls v0.9.0/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk=
github.com/marten-seemann/qtls v0.9.0/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
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-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.
4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU
=
github.com/mattn/go-runewidth v0.0.
6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k
=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
...
@@ -606,7 +557,6 @@ github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg
...
@@ -606,7 +557,6 @@ github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.1.2/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90=
github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI=
github.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI=
...
@@ -648,24 +598,24 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
...
@@ -648,24 +598,24 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.0.0-20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/naoina/toml v0.0.0-20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20190409134802-7e037d187b0c h1:2j4kdCOg5xiOVCTQpv0SgbzndaVJKliD6oRbMxTw6v4=
github.com/olekukonko/tablewriter v0.0.0-20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.0-20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
...
@@ -676,31 +626,28 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
...
@@ -676,31 +626,28 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/oschwald/maxminddb-golang v0.0.0-20180819230143-277d39ecb83e/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/oschwald/maxminddb-golang v0.0.0-20180819230143-277d39ecb83e/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222 h1:goeTyGkArOZIVOMA0dQbyuPWGNQJZGPwPu/QS9GlpnA=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
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.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterh/liner v0.0.0-20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/peterh/liner v0.0.0-20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.8.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.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 v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
...
@@ -708,8 +655,6 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
...
@@ -708,8 +655,6 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
...
@@ -719,16 +664,16 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
...
@@ -719,16 +664,16 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rnsdomains/rns-go-lib v0.0.0-20191114120302-3505575b0b8f/go.mod h1:kmfQJUbCUj/ZW6F2k6nWuoHGyXw7YW1Tl3YwzoRPTTU=
github.com/rnsdomains/rns-go-lib v0.0.0-20191114120302-3505575b0b8f/go.mod h1:kmfQJUbCUj/ZW6F2k6nWuoHGyXw7YW1Tl3YwzoRPTTU=
github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
github.com/rs/xhandler v0.0.0-20170707052532-1eb70cf1520d h1:8Tt7DYYdFqLlOIuyiE0RluKem4T+048AUafnIjH80wg=
github.com/rs/xhandler v0.0.0-20170707052532-1eb70cf1520d h1:8Tt7DYYdFqLlOIuyiE0RluKem4T+048AUafnIjH80wg=
github.com/rs/xhandler v0.0.0-20170707052532-1eb70cf1520d/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
github.com/rs/xhandler v0.0.0-20170707052532-1eb70cf1520d/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
...
@@ -763,7 +708,9 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
...
@@ -763,7 +708,9 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
...
@@ -773,7 +720,6 @@ github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7A
...
@@ -773,7 +720,6 @@ github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7A
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
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 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
...
@@ -792,57 +738,47 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
...
@@ -792,57 +738,47 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.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/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v0.0.0-20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/syndtr/goleveldb v0.0.0-20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tdewolff/minify/v2 v2.6.1/go.mod h1:l9hbQnH096st77OkscoRUvKdd23oUM6pDZpYx381sPo=
github.com/tdewolff/minify/v2 v2.7.3/go.mod h1:BkDSm8aMMT0ALGmpt7j3Ra7nLUgZL0qhyrAHXwxcy5w=
github.com/tdewolff/minify/v2 v2.7.3/go.mod h1:BkDSm8aMMT0ALGmpt7j3Ra7nLUgZL0qhyrAHXwxcy5w=
github.com/tdewolff/parse/v2 v2.3.14/go.mod h1:+V2lSZ93xpH2Csfs/vtNY1Fjr8kcFMsZKjyLoSkZbM0=
github.com/tdewolff/parse/v2 v2.4.1/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.4/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao=
github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tyler-smith/go-bip39 v0.0.0-20181017060643-dbb3b84ba2ef h1:luEzjJzktS9eU0CmI0uApXHLP/lKzOoRPrJhd71J8ik=
github.com/tyler-smith/go-bip39 v0.0.0-20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/tyler-smith/go-bip39 v0.0.0-20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7 h1:0M6xAhuJ/tVOsrSyesayxF8bqlfHjmUsXPrN4JAtJtI=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7 h1:0M6xAhuJ/tVOsrSyesayxF8bqlfHjmUsXPrN4JAtJtI=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/uber/jaeger-lib v1.5.0 h1:OHbgr8l656Ub3Fw5k9SWnBfIEwvoHQ+W2y+Aa9D1Uyo=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/whyrusleeping/go-logging v0.0.1 h1:fwpzlmT0kRC/Fmd0MdmGgJG/CXIZ6gFq46FQZjprUcc=
github.com/whyrusleeping/go-logging v0.0.1 h1:fwpzlmT0kRC/Fmd0MdmGgJG/CXIZ6gFq46FQZjprUcc=
...
@@ -854,6 +790,7 @@ github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84
...
@@ -854,6 +790,7 @@ github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
...
@@ -868,6 +805,7 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
...
@@ -868,6 +805,7 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
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/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
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.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
...
@@ -889,13 +827,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
...
@@ -889,13 +827,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 h1:aJ0ex187qoXrJHPo8ZasVTASQB7llQP6YeNzgDALPRk=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
...
@@ -904,6 +837,7 @@ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTk
...
@@ -904,6 +837,7 @@ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
...
@@ -927,10 +861,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
...
@@ -927,10 +861,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
...
@@ -973,19 +903,12 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
...
@@ -973,19 +903,12 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76 h1:Dho5nD6R3PcW2SH1or8vS0dszDaXRxIw55lBX7XiE5g=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
...
@@ -1009,6 +932,7 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
...
@@ -1009,6 +932,7 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/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-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
...
@@ -1031,7 +955,6 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn
...
@@ -1031,7 +955,6 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
...
@@ -1041,12 +964,12 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
...
@@ -1041,12 +964,12 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
...
@@ -1054,7 +977,6 @@ gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
...
@@ -1054,7 +977,6 @@ gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
...
@@ -1065,6 +987,7 @@ gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVY
...
@@ -1065,6 +987,7 @@ gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVY
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
...
@@ -1072,8 +995,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
...
@@ -1072,8 +995,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
...
@@ -1088,15 +1010,11 @@ k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
...
@@ -1088,15 +1010,11 @@ k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
resenje.org/daemon v0.1.2/go.mod h1:mF5JRpH3EbrxI9WoeKY78e6PqSsbBtX9jAQL5vj/GBA=
resenje.org/daemon v0.1.2/go.mod h1:mF5JRpH3EbrxI9WoeKY78e6PqSsbBtX9jAQL5vj/GBA=
resenje.org/email v0.1.2/go.mod h1:erp4uyQKjfJMEKrlG6JIWbMhFlUpIV+pkFptfJNm5uA=
resenje.org/email v0.1.3/go.mod h1:OhAVLRG3vqd9NSgayN3pAgzxTmc2B6mAefgShZvEgf0=
resenje.org/email v0.1.3/go.mod h1:OhAVLRG3vqd9NSgayN3pAgzxTmc2B6mAefgShZvEgf0=
resenje.org/jsonhttp v0.2.0/go.mod h1:EDyeguyTWj2fU3D3SCE0qNTgthzyEkHYLM1uu0uikHU=
resenje.org/jsonhttp v0.2.0/go.mod h1:EDyeguyTWj2fU3D3SCE0qNTgthzyEkHYLM1uu0uikHU=
resenje.org/jsonresponse v0.1.2/go.mod h1:L+alM0Xnew+XnpuINkpoyJI8Q6zaVKqmGkW8ELwzxs0=
resenje.org/logging v0.1.5/go.mod h1:1IdoCm3+UwYfsplxDGV2pHCkUrLlQzlWwp4r28XfPx4=
resenje.org/logging v0.1.5/go.mod h1:1IdoCm3+UwYfsplxDGV2pHCkUrLlQzlWwp4r28XfPx4=
resenje.org/marshal v0.1.1/go.mod h1:P7Cla6Ju5CFvW4Y8JbRgWX1Hcy4L1w4qcCsyadO7G94=
resenje.org/marshal v0.1.1/go.mod h1:P7Cla6Ju5CFvW4Y8JbRgWX1Hcy4L1w4qcCsyadO7G94=
resenje.org/recovery v0.1.1/go.mod h1:3S6aCVKMJEWsSAb61oZTteaiqkIfQPTr1RdiWnRbhME=
resenje.org/recovery v0.1.1/go.mod h1:3S6aCVKMJEWsSAb61oZTteaiqkIfQPTr1RdiWnRbhME=
resenje.org/web v0.4.0 h1:EBoea/NwSJIPAXhKdYUOEAvCG0IyQGB9AZLD44y9gEQ=
resenje.org/web v0.4.0/go.mod h1:NIqBGFkZRjbdpgpTjbo5UwXrzVSS0IaGX6QH4OHHcsg=
resenje.org/web v0.4.3 h1:G9vceKKGvsVg0WpyafJEEMHfstoxSO8rG/1Bo7fOkhw=
resenje.org/web v0.4.3 h1:G9vceKKGvsVg0WpyafJEEMHfstoxSO8rG/1Bo7fOkhw=
resenje.org/web v0.4.3/go.mod h1:GZw/Jt7IGIYlytsyGdAV5CytZnaQu7GV2u1LLuViihc=
resenje.org/web v0.4.3/go.mod h1:GZw/Jt7IGIYlytsyGdAV5CytZnaQu7GV2u1LLuViihc=
resenje.org/x v0.2.4/go.mod h1:1b2Xpo29FRc3IMvg/u46/IyjySl5IjvtuSjXTA/AOnk=
resenje.org/x v0.2.4/go.mod h1:1b2Xpo29FRc3IMvg/u46/IyjySl5IjvtuSjXTA/AOnk=
...
...
pkg/storage/localstore/doc.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
/*
Package localstore provides disk storage layer for Swarm Chunk persistence.
It uses swarm/shed abstractions on top of github.com/syndtr/goleveldb LevelDB
implementation.
The main type is DB which manages the storage by providing methods to
access and add Chunks and to manage their status.
Modes are abstractions that do specific changes to Chunks. There are three
mode types:
- ModeGet, for Chunk access
- ModePut, for adding Chunks to the database
- ModeSet, for changing Chunk statuses
Every mode type has a corresponding type (Getter, Putter and Setter)
that provides adequate method to perform the opperation and that type
should be injected into localstore consumers instead the whole DB.
This provides more clear insight which operations consumer is performing
on the database.
Getters, Putters and Setters accept different get, put and set modes
to perform different actions. For example, ModeGet has two different
variables ModeGetRequest and ModeGetSync and two different Getters
can be constructed with them that are used when the chunk is requested
or when the chunk is synced as this two events are differently changing
the database.
Subscription methods are implemented for a specific purpose of
continuous iterations over Chunks that should be provided to
Push and Pull syncing.
DB implements an internal garbage collector that removes only synced
Chunks from the database based on their most recent access time.
Internally, DB stores Chunk data and any required information, such as
store and access timestamps in different shed indexes that can be
iterated on by garbage collector or subscriptions.
*/
package
localstore
pkg/storage/localstore/export.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"archive/tar"
"context"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"sync"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/log"
"github.com/ethersphere/swarm/shed"
)
const
(
// filename in tar archive that holds the information
// about exported data format version
exportVersionFilename
=
".swarm-export-version"
// legacy version for previous LDBStore
legacyExportVersion
=
"1"
// current export format version
currentExportVersion
=
"2"
)
// Export writes a tar structured data to the writer of
// all chunks in the retrieval data index. It returns the
// number of chunks exported.
func
(
db
*
DB
)
Export
(
w
io
.
Writer
)
(
count
int64
,
err
error
)
{
tw
:=
tar
.
NewWriter
(
w
)
defer
tw
.
Close
()
if
err
:=
tw
.
WriteHeader
(
&
tar
.
Header
{
Name
:
exportVersionFilename
,
Mode
:
0644
,
Size
:
int64
(
len
(
currentExportVersion
)),
});
err
!=
nil
{
return
0
,
err
}
if
_
,
err
:=
tw
.
Write
([]
byte
(
currentExportVersion
));
err
!=
nil
{
return
0
,
err
}
err
=
db
.
retrievalDataIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
hdr
:=
&
tar
.
Header
{
Name
:
hex
.
EncodeToString
(
item
.
Address
),
Mode
:
0644
,
Size
:
int64
(
len
(
item
.
Data
)),
}
if
err
:=
tw
.
WriteHeader
(
hdr
);
err
!=
nil
{
return
false
,
err
}
if
_
,
err
:=
tw
.
Write
(
item
.
Data
);
err
!=
nil
{
return
false
,
err
}
count
++
return
false
,
nil
},
nil
)
return
count
,
err
}
// Import reads a tar structured data from the reader and
// stores chunks in the database. It returns the number of
// chunks imported.
func
(
db
*
DB
)
Import
(
r
io
.
Reader
,
legacy
bool
)
(
count
int64
,
err
error
)
{
tr
:=
tar
.
NewReader
(
r
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
errC
:=
make
(
chan
error
)
doneC
:=
make
(
chan
struct
{})
tokenPool
:=
make
(
chan
struct
{},
100
)
var
wg
sync
.
WaitGroup
go
func
()
{
var
(
firstFile
=
true
// if exportVersionFilename file is not present
// assume legacy version
version
=
legacyExportVersion
)
for
{
hdr
,
err
:=
tr
.
Next
()
if
err
!=
nil
{
if
err
==
io
.
EOF
{
break
}
select
{
case
errC
<-
err
:
case
<-
ctx
.
Done
()
:
}
}
if
firstFile
{
firstFile
=
false
if
hdr
.
Name
==
exportVersionFilename
{
data
,
err
:=
ioutil
.
ReadAll
(
tr
)
if
err
!=
nil
{
select
{
case
errC
<-
err
:
case
<-
ctx
.
Done
()
:
}
}
version
=
string
(
data
)
continue
}
}
if
len
(
hdr
.
Name
)
!=
64
{
log
.
Warn
(
"ignoring non-chunk file"
,
"name"
,
hdr
.
Name
)
continue
}
keybytes
,
err
:=
hex
.
DecodeString
(
hdr
.
Name
)
if
err
!=
nil
{
log
.
Warn
(
"ignoring invalid chunk file"
,
"name"
,
hdr
.
Name
,
"err"
,
err
)
continue
}
data
,
err
:=
ioutil
.
ReadAll
(
tr
)
if
err
!=
nil
{
select
{
case
errC
<-
err
:
case
<-
ctx
.
Done
()
:
}
}
key
:=
chunk
.
Address
(
keybytes
)
var
ch
chunk
.
Chunk
switch
version
{
case
legacyExportVersion
:
// LDBStore Export exported chunk data prefixed with the chunk key.
// That is not necessary, as the key is in the chunk filename,
// but backward compatibility needs to be preserved.
ch
=
chunk
.
NewChunk
(
key
,
data
[
32
:
])
case
currentExportVersion
:
ch
=
chunk
.
NewChunk
(
key
,
data
)
default
:
select
{
case
errC
<-
fmt
.
Errorf
(
"unsupported export data version %q"
,
version
)
:
case
<-
ctx
.
Done
()
:
}
}
tokenPool
<-
struct
{}{}
wg
.
Add
(
1
)
go
func
()
{
_
,
err
:=
db
.
Put
(
ctx
,
chunk
.
ModePutUpload
,
ch
)
select
{
case
errC
<-
err
:
case
<-
ctx
.
Done
()
:
wg
.
Done
()
<-
tokenPool
default
:
_
,
err
:=
db
.
Put
(
ctx
,
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
errC
<-
err
}
wg
.
Done
()
<-
tokenPool
}
}()
count
++
}
wg
.
Wait
()
close
(
doneC
)
}()
// wait for all chunks to be stored
for
{
select
{
case
err
:=
<-
errC
:
if
err
!=
nil
{
return
count
,
err
}
case
<-
ctx
.
Done
()
:
return
count
,
ctx
.
Err
()
default
:
select
{
case
<-
doneC
:
return
count
,
nil
default
:
}
}
}
}
pkg/storage/localstore/export_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"testing"
"github.com/ethersphere/swarm/chunk"
)
// TestExportImport constructs two databases, one to put and export
// chunks and another one to import and validate that all chunks are
// imported.
func
TestExportImport
(
t
*
testing
.
T
)
{
db1
,
cleanup1
:=
newTestDB
(
t
,
nil
)
defer
cleanup1
()
var
chunkCount
=
100
chunks
:=
make
(
map
[
string
][]
byte
,
chunkCount
)
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db1
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
[
string
(
ch
.
Address
())]
=
ch
.
Data
()
}
var
buf
bytes
.
Buffer
c
,
err
:=
db1
.
Export
(
&
buf
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
wantChunksCount
:=
int64
(
len
(
chunks
))
if
c
!=
wantChunksCount
{
t
.
Errorf
(
"got export count %v, want %v"
,
c
,
wantChunksCount
)
}
db2
,
cleanup2
:=
newTestDB
(
t
,
nil
)
defer
cleanup2
()
c
,
err
=
db2
.
Import
(
&
buf
,
false
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
c
!=
wantChunksCount
{
t
.
Errorf
(
"got import count %v, want %v"
,
c
,
wantChunksCount
)
}
for
a
,
want
:=
range
chunks
{
addr
:=
chunk
.
Address
([]
byte
(
a
))
ch
,
err
:=
db2
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addr
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
got
:=
ch
.
Data
()
if
!
bytes
.
Equal
(
got
,
want
)
{
t
.
Fatalf
(
"chunk %s: got data %x, want %x"
,
addr
.
Hex
(),
got
,
want
)
}
}
}
pkg/storage/localstore/gc.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
var
(
// gcTargetRatio defines the target number of items
// in garbage collection index that will not be removed
// on garbage collection. The target number of items
// is calculated by gcTarget function. This value must be
// in range (0,1]. For example, with 0.9 value,
// garbage collection will leave 90% of defined capacity
// in database after its run. This prevents frequent
// garbage collection runs.
gcTargetRatio
=
0.9
// gcBatchSize limits the number of chunks in a single
// leveldb batch on garbage collection.
gcBatchSize
uint64
=
200
)
// collectGarbageWorker is a long running function that waits for
// collectGarbageTrigger channel to signal a garbage collection
// run. GC run iterates on gcIndex and removes older items
// form retrieval and other indexes.
func
(
db
*
DB
)
collectGarbageWorker
()
{
defer
close
(
db
.
collectGarbageWorkerDone
)
for
{
select
{
case
<-
db
.
collectGarbageTrigger
:
// run a single collect garbage run and
// if done is false, gcBatchSize is reached and
// another collect garbage run is needed
collectedCount
,
done
,
err
:=
db
.
collectGarbage
()
if
err
!=
nil
{
log
.
Error
(
"localstore collect garbage"
,
"err"
,
err
)
}
// check if another gc run is needed
if
!
done
{
db
.
triggerGarbageCollection
()
}
if
testHookCollectGarbage
!=
nil
{
testHookCollectGarbage
(
collectedCount
)
}
case
<-
db
.
close
:
return
}
}
}
// collectGarbage removes chunks from retrieval and other
// indexes if maximal number of chunks in database is reached.
// This function returns the number of removed chunks. If done
// is false, another call to this function is needed to collect
// the rest of the garbage as the batch size limit is reached.
// This function is called in collectGarbageWorker.
func
(
db
*
DB
)
collectGarbage
()
(
collectedCount
uint64
,
done
bool
,
err
error
)
{
metricName
:=
"localstore/gc"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
defer
func
()
{
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
}()
batch
:=
new
(
leveldb
.
Batch
)
target
:=
db
.
gcTarget
()
// protect database from changing idexes and gcSize
db
.
batchMu
.
Lock
()
defer
db
.
batchMu
.
Unlock
()
// run through the recently pinned chunks and
// remove them from the gcIndex before iterating through gcIndex
err
=
db
.
removeChunksInExcludeIndexFromGC
()
if
err
!=
nil
{
log
.
Error
(
"localstore exclude pinned chunks"
,
"err"
,
err
)
return
0
,
true
,
err
}
gcSize
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
return
0
,
true
,
err
}
metrics
.
GetOrRegisterGauge
(
metricName
+
"/gcsize"
,
nil
)
.
Update
(
int64
(
gcSize
))
done
=
true
err
=
db
.
gcIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
if
gcSize
-
collectedCount
<=
target
{
return
true
,
nil
}
metrics
.
GetOrRegisterGauge
(
metricName
+
"/storets"
,
nil
)
.
Update
(
item
.
StoreTimestamp
)
metrics
.
GetOrRegisterGauge
(
metricName
+
"/accessts"
,
nil
)
.
Update
(
item
.
AccessTimestamp
)
// delete from retrieve, pull, gc
err
=
db
.
retrievalDataIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
true
,
nil
}
err
=
db
.
retrievalAccessIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
true
,
nil
}
err
=
db
.
pullIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
true
,
nil
}
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
true
,
nil
}
collectedCount
++
if
collectedCount
>=
gcBatchSize
{
// bach size limit reached,
// another gc run is needed
done
=
false
return
true
,
nil
}
return
false
,
nil
},
nil
)
if
err
!=
nil
{
return
0
,
false
,
err
}
metrics
.
GetOrRegisterCounter
(
metricName
+
"/collected-count"
,
nil
)
.
Inc
(
int64
(
collectedCount
))
db
.
gcSize
.
PutInBatch
(
batch
,
gcSize
-
collectedCount
)
err
=
db
.
shed
.
WriteBatch
(
batch
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/writebatch/err"
,
nil
)
.
Inc
(
1
)
return
0
,
false
,
err
}
return
collectedCount
,
done
,
nil
}
// removeChunksInExcludeIndexFromGC removed any recently chunks in the exclude Index, from the gcIndex.
func
(
db
*
DB
)
removeChunksInExcludeIndexFromGC
()
(
err
error
)
{
metricName
:=
"localstore/gc/exclude"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
defer
func
()
{
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
}()
batch
:=
new
(
leveldb
.
Batch
)
excludedCount
:=
0
var
gcSizeChange
int64
err
=
db
.
gcExcludeIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
// Get access timestamp
retrievalAccessIndexItem
,
err
:=
db
.
retrievalAccessIndex
.
Get
(
item
)
if
err
!=
nil
{
return
false
,
err
}
item
.
AccessTimestamp
=
retrievalAccessIndexItem
.
AccessTimestamp
// Get the binId
retrievalDataIndexItem
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
return
false
,
err
}
item
.
BinID
=
retrievalDataIndexItem
.
BinID
// Check if this item is in gcIndex and remove it
ok
,
err
:=
db
.
gcIndex
.
Has
(
item
)
if
err
!=
nil
{
return
false
,
nil
}
if
ok
{
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
nil
}
if
_
,
err
:=
db
.
gcIndex
.
Get
(
item
);
err
==
nil
{
gcSizeChange
--
}
excludedCount
++
err
=
db
.
gcExcludeIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
nil
}
}
return
false
,
nil
},
nil
)
if
err
!=
nil
{
return
err
}
// update the gc size based on the no of entries deleted in gcIndex
err
=
db
.
incGCSizeInBatch
(
batch
,
gcSizeChange
)
if
err
!=
nil
{
return
err
}
metrics
.
GetOrRegisterCounter
(
metricName
+
"/excluded-count"
,
nil
)
.
Inc
(
int64
(
excludedCount
))
err
=
db
.
shed
.
WriteBatch
(
batch
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/writebatch/err"
,
nil
)
.
Inc
(
1
)
return
err
}
return
nil
}
// gcTrigger retruns the absolute value for garbage collection
// target value, calculated from db.capacity and gcTargetRatio.
func
(
db
*
DB
)
gcTarget
()
(
target
uint64
)
{
return
uint64
(
float64
(
db
.
capacity
)
*
gcTargetRatio
)
}
// triggerGarbageCollection signals collectGarbageWorker
// to call collectGarbage.
func
(
db
*
DB
)
triggerGarbageCollection
()
{
select
{
case
db
.
collectGarbageTrigger
<-
struct
{}{}
:
case
<-
db
.
close
:
default
:
}
}
// incGCSizeInBatch changes gcSize field value
// by change which can be negative. This function
// must be called under batchMu lock.
func
(
db
*
DB
)
incGCSizeInBatch
(
batch
*
leveldb
.
Batch
,
change
int64
)
(
err
error
)
{
if
change
==
0
{
return
nil
}
gcSize
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
return
err
}
var
new
uint64
if
change
>
0
{
new
=
gcSize
+
uint64
(
change
)
}
else
{
// 'change' is an int64 and is negative
// a conversion is needed with correct sign
c
:=
uint64
(
-
change
)
if
c
>
gcSize
{
// protect uint64 undeflow
return
nil
}
new
=
gcSize
-
c
}
db
.
gcSize
.
PutInBatch
(
batch
,
new
)
// trigger garbage collection if we reached the capacity
if
new
>=
db
.
capacity
{
db
.
triggerGarbageCollection
()
}
return
nil
}
// testHookCollectGarbage is a hook that can provide
// information when a garbage collection run is done
// and how many items it removed.
var
testHookCollectGarbage
func
(
collectedCount
uint64
)
pkg/storage/localstore/gc_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"io/ioutil"
"math/rand"
"os"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
)
// TestDB_collectGarbageWorker tests garbage collection runs
// by uploading and syncing a number of chunks.
func
TestDB_collectGarbageWorker
(
t
*
testing
.
T
)
{
testDBCollectGarbageWorker
(
t
)
}
// TestDB_collectGarbageWorker_multipleBatches tests garbage
// collection runs by uploading and syncing a number of
// chunks by having multiple smaller batches.
func
TestDB_collectGarbageWorker_multipleBatches
(
t
*
testing
.
T
)
{
// lower the maximal number of chunks in a single
// gc batch to ensure multiple batches.
defer
func
(
s
uint64
)
{
gcBatchSize
=
s
}(
gcBatchSize
)
gcBatchSize
=
2
testDBCollectGarbageWorker
(
t
)
}
// testDBCollectGarbageWorker is a helper test function to test
// garbage collection runs by uploading and syncing a number of chunks.
func
testDBCollectGarbageWorker
(
t
*
testing
.
T
)
{
chunkCount
:=
150
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Capacity
:
100
,
})
testHookCollectGarbageChan
:=
make
(
chan
uint64
)
defer
setTestHookCollectGarbage
(
func
(
collectedCount
uint64
)
{
select
{
case
testHookCollectGarbageChan
<-
collectedCount
:
case
<-
db
.
close
:
}
})()
defer
cleanupFunc
()
addrs
:=
make
([]
chunk
.
Address
,
0
)
// upload random chunks
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addrs
=
append
(
addrs
,
ch
.
Address
())
}
gcTarget
:=
db
.
gcTarget
()
for
{
select
{
case
<-
testHookCollectGarbageChan
:
case
<-
time
.
After
(
10
*
time
.
Second
)
:
t
.
Error
(
"collect garbage timeout"
)
}
gcSize
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
gcSize
==
gcTarget
{
break
}
}
t
.
Run
(
"pull index count"
,
newItemsCountTest
(
db
.
pullIndex
,
int
(
gcTarget
)))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
int
(
gcTarget
)))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
// the first synced chunk should be removed
t
.
Run
(
"get the first synced chunk"
,
func
(
t
*
testing
.
T
)
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
0
])
if
err
!=
chunk
.
ErrChunkNotFound
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
chunk
.
ErrChunkNotFound
)
}
})
t
.
Run
(
"only first inserted chunks should be removed"
,
func
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
(
chunkCount
-
int
(
gcTarget
));
i
++
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
i
])
if
err
!=
chunk
.
ErrChunkNotFound
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
chunk
.
ErrChunkNotFound
)
}
}
})
// last synced chunk should not be removed
t
.
Run
(
"get most recent synced chunk"
,
func
(
t
*
testing
.
T
)
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
len
(
addrs
)
-
1
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
})
}
// Pin a file, upload chunks to go past the gc limit to trigger GC,
// check if the pinned files are still around and removed from gcIndex
func
TestPinGC
(
t
*
testing
.
T
)
{
chunkCount
:=
150
pinChunksCount
:=
50
dbCapacity
:=
uint64
(
100
)
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Capacity
:
dbCapacity
,
})
testHookCollectGarbageChan
:=
make
(
chan
uint64
)
defer
setTestHookCollectGarbage
(
func
(
collectedCount
uint64
)
{
select
{
case
testHookCollectGarbageChan
<-
collectedCount
:
case
<-
db
.
close
:
}
})()
defer
cleanupFunc
()
addrs
:=
make
([]
chunk
.
Address
,
0
)
pinAddrs
:=
make
([]
chunk
.
Address
,
0
)
// upload random chunks
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addrs
=
append
(
addrs
,
ch
.
Address
())
// Pin the chunks at the beginning to make sure they are not removed by GC
if
i
<
pinChunksCount
{
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetPin
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
pinAddrs
=
append
(
pinAddrs
,
ch
.
Address
())
}
}
gcTarget
:=
db
.
gcTarget
()
for
{
select
{
case
<-
testHookCollectGarbageChan
:
case
<-
time
.
After
(
10
*
time
.
Second
)
:
t
.
Error
(
"collect garbage timeout"
)
}
gcSize
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
gcSize
==
gcTarget
{
break
}
}
t
.
Run
(
"pin Index count"
,
newItemsCountTest
(
db
.
pinIndex
,
pinChunksCount
))
t
.
Run
(
"gc exclude index count"
,
newItemsCountTest
(
db
.
gcExcludeIndex
,
0
))
t
.
Run
(
"pull index count"
,
newItemsCountTest
(
db
.
pullIndex
,
int
(
gcTarget
)
+
pinChunksCount
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
int
(
gcTarget
)))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
t
.
Run
(
"pinned chunk not in gc Index"
,
func
(
t
*
testing
.
T
)
{
err
:=
db
.
gcIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
for
_
,
pinHash
:=
range
pinAddrs
{
if
bytes
.
Equal
(
pinHash
,
item
.
Address
)
{
t
.
Fatal
(
"pin chunk present in gcIndex"
)
}
}
return
false
,
nil
},
nil
)
if
err
!=
nil
{
t
.
Fatal
(
"could not iterate gcIndex"
)
}
})
t
.
Run
(
"pinned chunks exists"
,
func
(
t
*
testing
.
T
)
{
for
_
,
hash
:=
range
pinAddrs
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
hash
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
})
t
.
Run
(
"first chunks after pinned chunks should be removed"
,
func
(
t
*
testing
.
T
)
{
for
i
:=
pinChunksCount
;
i
<
(
int
(
dbCapacity
)
-
int
(
gcTarget
));
i
++
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
i
])
if
err
!=
chunk
.
ErrChunkNotFound
{
t
.
Fatal
(
err
)
}
}
})
}
// Upload chunks, pin those chunks, add to GC after it is pinned
// check if the pinned files are still around
func
TestGCAfterPin
(
t
*
testing
.
T
)
{
chunkCount
:=
50
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Capacity
:
100
,
})
defer
cleanupFunc
()
pinAddrs
:=
make
([]
chunk
.
Address
,
0
)
// upload random chunks
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// Pin before adding to GC in ModeSetSyncPull
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetPin
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
pinAddrs
=
append
(
pinAddrs
,
ch
.
Address
())
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
t
.
Run
(
"pin Index count"
,
newItemsCountTest
(
db
.
pinIndex
,
chunkCount
))
t
.
Run
(
"gc exclude index count"
,
newItemsCountTest
(
db
.
gcExcludeIndex
,
chunkCount
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
int
(
0
)))
for
_
,
hash
:=
range
pinAddrs
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
hash
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
}
// TestDB_collectGarbageWorker_withRequests is a helper test function
// to test garbage collection runs by uploading, syncing and
// requesting a number of chunks.
func
TestDB_collectGarbageWorker_withRequests
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Capacity
:
100
,
})
defer
cleanupFunc
()
testHookCollectGarbageChan
:=
make
(
chan
uint64
)
defer
setTestHookCollectGarbage
(
func
(
collectedCount
uint64
)
{
testHookCollectGarbageChan
<-
collectedCount
})()
addrs
:=
make
([]
chunk
.
Address
,
0
)
// upload random chunks just up to the capacity
for
i
:=
0
;
i
<
int
(
db
.
capacity
)
-
1
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addrs
=
append
(
addrs
,
ch
.
Address
())
}
// set update gc test hook to signal when
// update gc goroutine is done by closing
// testHookUpdateGCChan channel
testHookUpdateGCChan
:=
make
(
chan
struct
{})
resetTestHookUpdateGC
:=
setTestHookUpdateGC
(
func
()
{
close
(
testHookUpdateGCChan
)
})
// request the latest synced chunk
// to prioritize it in the gc index
// not to be collected
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
0
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to finish for garbage
// collector to be correctly triggered after the last upload
select
{
case
<-
testHookUpdateGCChan
:
case
<-
time
.
After
(
10
*
time
.
Second
)
:
t
.
Fatal
(
"updateGC was not called after getting chunk with ModeGetRequest"
)
}
// no need to wait for update gc hook anymore
resetTestHookUpdateGC
()
// upload and sync another chunk to trigger
// garbage collection
ch
:=
generateTestRandomChunk
()
_
,
err
=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addrs
=
append
(
addrs
,
ch
.
Address
())
// wait for garbage collection
gcTarget
:=
db
.
gcTarget
()
var
totalCollectedCount
uint64
for
{
select
{
case
c
:=
<-
testHookCollectGarbageChan
:
totalCollectedCount
+=
c
case
<-
time
.
After
(
10
*
time
.
Second
)
:
t
.
Error
(
"collect garbage timeout"
)
}
gcSize
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
gcSize
==
gcTarget
{
break
}
}
wantTotalCollectedCount
:=
uint64
(
len
(
addrs
))
-
gcTarget
if
totalCollectedCount
!=
wantTotalCollectedCount
{
t
.
Errorf
(
"total collected chunks %v, want %v"
,
totalCollectedCount
,
wantTotalCollectedCount
)
}
t
.
Run
(
"pull index count"
,
newItemsCountTest
(
db
.
pullIndex
,
int
(
gcTarget
)))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
int
(
gcTarget
)))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
// requested chunk should not be removed
t
.
Run
(
"get requested chunk"
,
func
(
t
*
testing
.
T
)
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
0
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
})
// the second synced chunk should be removed
t
.
Run
(
"get gc-ed chunk"
,
func
(
t
*
testing
.
T
)
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
1
])
if
err
!=
chunk
.
ErrChunkNotFound
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
chunk
.
ErrChunkNotFound
)
}
})
// last synced chunk should not be removed
t
.
Run
(
"get most recent synced chunk"
,
func
(
t
*
testing
.
T
)
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
len
(
addrs
)
-
1
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
})
}
// TestDB_gcSize checks if gcSize has a correct value after
// database is initialized with existing data.
func
TestDB_gcSize
(
t
*
testing
.
T
)
{
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-stored-gc-size"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
dir
)
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
db
,
err
:=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
count
:=
100
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
if
err
:=
db
.
Close
();
err
!=
nil
{
t
.
Fatal
(
err
)
}
db
,
err
=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
db
.
Close
()
t
.
Run
(
"gc index size"
,
newIndexGCSizeTest
(
db
))
}
// setTestHookCollectGarbage sets testHookCollectGarbage and
// returns a function that will reset it to the
// value before the change.
func
setTestHookCollectGarbage
(
h
func
(
collectedCount
uint64
))
(
reset
func
())
{
current
:=
testHookCollectGarbage
reset
=
func
()
{
testHookCollectGarbage
=
current
}
testHookCollectGarbage
=
h
return
reset
}
// TestSetTestHookCollectGarbage tests if setTestHookCollectGarbage changes
// testHookCollectGarbage function correctly and if its reset function
// resets the original function.
func
TestSetTestHookCollectGarbage
(
t
*
testing
.
T
)
{
// Set the current function after the test finishes.
defer
func
(
h
func
(
collectedCount
uint64
))
{
testHookCollectGarbage
=
h
}(
testHookCollectGarbage
)
// expected value for the unchanged function
original
:=
1
// expected value for the changed function
changed
:=
2
// this variable will be set with two different functions
var
got
int
// define the original (unchanged) functions
testHookCollectGarbage
=
func
(
_
uint64
)
{
got
=
original
}
// set got variable
testHookCollectGarbage
(
0
)
// test if got variable is set correctly
if
got
!=
original
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
original
)
}
// set the new function
reset
:=
setTestHookCollectGarbage
(
func
(
_
uint64
)
{
got
=
changed
})
// set got variable
testHookCollectGarbage
(
0
)
// test if got variable is set correctly to changed value
if
got
!=
changed
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
changed
)
}
// set the function to the original one
reset
()
// set got variable
testHookCollectGarbage
(
0
)
// test if got variable is set correctly to original value
if
got
!=
original
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
original
)
}
}
pkg/storage/localstore/index_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"math/rand"
"testing"
"github.com/ethersphere/swarm/chunk"
)
// TestDB_pullIndex validates the ordering of keys in pull index.
// Pull index key contains PO prefix which is calculated from
// DB base key and chunk address. This is not an Item field
// which are checked in Mode tests.
// This test uploads chunks, sorts them in expected order and
// validates that pull index iterator will iterate it the same
// order.
func
TestDB_pullIndex
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunkCount
:=
50
chunks
:=
make
([]
testIndexChunk
,
chunkCount
)
// upload random chunks
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
[
i
]
=
testIndexChunk
{
Chunk
:
ch
,
binID
:
uint64
(
i
),
}
}
testItemsOrder
(
t
,
db
.
pullIndex
,
chunks
,
func
(
i
,
j
int
)
(
less
bool
)
{
poi
:=
chunk
.
Proximity
(
db
.
baseKey
,
chunks
[
i
]
.
Address
())
poj
:=
chunk
.
Proximity
(
db
.
baseKey
,
chunks
[
j
]
.
Address
())
if
poi
<
poj
{
return
true
}
if
poi
>
poj
{
return
false
}
if
chunks
[
i
]
.
binID
<
chunks
[
j
]
.
binID
{
return
true
}
if
chunks
[
i
]
.
binID
>
chunks
[
j
]
.
binID
{
return
false
}
return
bytes
.
Compare
(
chunks
[
i
]
.
Address
(),
chunks
[
j
]
.
Address
())
==
-
1
})
}
// TestDB_gcIndex validates garbage collection index by uploading
// a chunk with and performing operations using synced, access and
// request modes.
func
TestDB_gcIndex
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunkCount
:=
50
chunks
:=
make
([]
testIndexChunk
,
chunkCount
)
// upload random chunks
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
[
i
]
=
testIndexChunk
{
Chunk
:
ch
,
}
}
// check if all chunks are stored
newItemsCountTest
(
db
.
pullIndex
,
chunkCount
)(
t
)
// check that chunks are not collectable for garbage
newItemsCountTest
(
db
.
gcIndex
,
0
)(
t
)
// set update gc test hook to signal when
// update gc goroutine is done by sending to
// testHookUpdateGCChan channel, which is
// used to wait for indexes change verifications
testHookUpdateGCChan
:=
make
(
chan
struct
{})
defer
setTestHookUpdateGC
(
func
()
{
testHookUpdateGCChan
<-
struct
{}{}
})()
t
.
Run
(
"request unsynced"
,
func
(
t
*
testing
.
T
)
{
ch
:=
chunks
[
1
]
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
// the chunk is not synced
// should not be in the garbace collection index
newItemsCountTest
(
db
.
gcIndex
,
0
)(
t
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"sync one chunk"
,
func
(
t
*
testing
.
T
)
{
ch
:=
chunks
[
0
]
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// the chunk is synced and should be in gc index
newItemsCountTest
(
db
.
gcIndex
,
1
)(
t
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"sync all chunks"
,
func
(
t
*
testing
.
T
)
{
for
i
:=
range
chunks
{
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
chunks
[
i
]
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
testItemsOrder
(
t
,
db
.
gcIndex
,
chunks
,
nil
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"request one chunk"
,
func
(
t
*
testing
.
T
)
{
i
:=
6
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
chunks
[
i
]
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
// move the chunk to the end of the expected gc
c
:=
chunks
[
i
]
chunks
=
append
(
chunks
[
:
i
],
chunks
[
i
+
1
:
]
...
)
chunks
=
append
(
chunks
,
c
)
testItemsOrder
(
t
,
db
.
gcIndex
,
chunks
,
nil
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"random chunk request"
,
func
(
t
*
testing
.
T
)
{
rand
.
Shuffle
(
len
(
chunks
),
func
(
i
,
j
int
)
{
chunks
[
i
],
chunks
[
j
]
=
chunks
[
j
],
chunks
[
i
]
})
for
_
,
ch
:=
range
chunks
{
_
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
}
testItemsOrder
(
t
,
db
.
gcIndex
,
chunks
,
nil
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"remove one chunk"
,
func
(
t
*
testing
.
T
)
{
i
:=
3
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetRemove
,
chunks
[
i
]
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// remove the chunk from the expected chunks in gc index
chunks
=
append
(
chunks
[
:
i
],
chunks
[
i
+
1
:
]
...
)
testItemsOrder
(
t
,
db
.
gcIndex
,
chunks
,
nil
)
newIndexGCSizeTest
(
db
)(
t
)
})
}
pkg/storage/localstore/localstore.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"encoding/binary"
"errors"
"os"
"runtime/pprof"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
"github.com/ethersphere/swarm/storage/mock"
)
// DB implements chunk.Store.
var
_
chunk
.
Store
=
&
DB
{}
var
(
// ErrInvalidMode is retuned when an unknown Mode
// is provided to the function.
ErrInvalidMode
=
errors
.
New
(
"invalid mode"
)
// ErrAddressLockTimeout is returned when the same chunk
// is updated in parallel and one of the updates
// takes longer then the configured timeout duration.
ErrAddressLockTimeout
=
errors
.
New
(
"address lock timeout"
)
)
var
(
// Default value for Capacity DB option.
defaultCapacity
uint64
=
5000000
// Limit the number of goroutines created by Getters
// that call updateGC function. Value 0 sets no limit.
maxParallelUpdateGC
=
1000
)
// DB is the local store implementation and holds
// database related objects.
type
DB
struct
{
shed
*
shed
.
DB
tags
*
chunk
.
Tags
// schema name of loaded data
schemaName
shed
.
StringField
// retrieval indexes
retrievalDataIndex
shed
.
Index
retrievalAccessIndex
shed
.
Index
// push syncing index
pushIndex
shed
.
Index
// push syncing subscriptions triggers
pushTriggers
[]
chan
struct
{}
pushTriggersMu
sync
.
RWMutex
// pull syncing index
pullIndex
shed
.
Index
// pull syncing subscriptions triggers per bin
pullTriggers
map
[
uint8
][]
chan
struct
{}
pullTriggersMu
sync
.
RWMutex
// binIDs stores the latest chunk serial ID for every
// proximity order bin
binIDs
shed
.
Uint64Vector
// garbage collection index
gcIndex
shed
.
Index
// garbage collection exclude index for pinned contents
gcExcludeIndex
shed
.
Index
// pin files Index
pinIndex
shed
.
Index
// field that stores number of intems in gc index
gcSize
shed
.
Uint64Field
// garbage collection is triggered when gcSize exceeds
// the capacity value
capacity
uint64
// triggers garbage collection event loop
collectGarbageTrigger
chan
struct
{}
// a buffered channel acting as a semaphore
// to limit the maximal number of goroutines
// created by Getters to call updateGC function
updateGCSem
chan
struct
{}
// a wait group to ensure all updateGC goroutines
// are done before closing the database
updateGCWG
sync
.
WaitGroup
baseKey
[]
byte
batchMu
sync
.
Mutex
// this channel is closed when close function is called
// to terminate other goroutines
close
chan
struct
{}
// protect Close method from exiting before
// garbage collection and gc size write workers
// are done
collectGarbageWorkerDone
chan
struct
{}
putToGCCheck
func
([]
byte
)
bool
// wait for all subscriptions to finish before closing
// underlaying LevelDB to prevent possible panics from
// iterators
subscritionsWG
sync
.
WaitGroup
}
// Options struct holds optional parameters for configuring DB.
type
Options
struct
{
// MockStore is a mock node store that is used to store
// chunk data in a central store. It can be used to reduce
// total storage space requirements in testing large number
// of swarm nodes with chunk data deduplication provided by
// the mock global store.
MockStore
*
mock
.
NodeStore
// Capacity is a limit that triggers garbage collection when
// number of items in gcIndex equals or exceeds it.
Capacity
uint64
// MetricsPrefix defines a prefix for metrics names.
MetricsPrefix
string
Tags
*
chunk
.
Tags
// PutSetCheckFunc is a function called after a Put of a chunk
// to verify whether that chunk needs to be Set and added to
// garbage collection index too
PutToGCCheck
func
([]
byte
)
bool
}
// New returns a new DB. All fields and indexes are initialized
// and possible conflicts with schema from existing database is checked.
// One goroutine for writing batches is created.
func
New
(
path
string
,
baseKey
[]
byte
,
o
*
Options
)
(
db
*
DB
,
err
error
)
{
if
o
==
nil
{
// default options
o
=
&
Options
{
Capacity
:
defaultCapacity
,
}
}
if
o
.
PutToGCCheck
==
nil
{
o
.
PutToGCCheck
=
func
(
_
[]
byte
)
bool
{
return
false
}
}
db
=
&
DB
{
capacity
:
o
.
Capacity
,
baseKey
:
baseKey
,
tags
:
o
.
Tags
,
// channel collectGarbageTrigger
// needs to be buffered with the size of 1
// to signal another event if it
// is triggered during already running function
collectGarbageTrigger
:
make
(
chan
struct
{},
1
),
close
:
make
(
chan
struct
{}),
collectGarbageWorkerDone
:
make
(
chan
struct
{}),
putToGCCheck
:
o
.
PutToGCCheck
,
}
if
db
.
capacity
==
0
{
db
.
capacity
=
defaultCapacity
}
if
maxParallelUpdateGC
>
0
{
db
.
updateGCSem
=
make
(
chan
struct
{},
maxParallelUpdateGC
)
}
db
.
shed
,
err
=
shed
.
NewDB
(
path
,
o
.
MetricsPrefix
)
if
err
!=
nil
{
return
nil
,
err
}
// Identify current storage schema by arbitrary name.
db
.
schemaName
,
err
=
db
.
shed
.
NewStringField
(
"schema-name"
)
if
err
!=
nil
{
return
nil
,
err
}
schemaName
,
err
:=
db
.
schemaName
.
Get
()
if
err
!=
nil
{
return
nil
,
err
}
if
schemaName
==
""
{
// initial new localstore run
err
:=
db
.
schemaName
.
Put
(
DbSchemaCurrent
)
if
err
!=
nil
{
return
nil
,
err
}
}
else
{
// execute possible migrations
err
=
db
.
migrate
(
schemaName
)
if
err
!=
nil
{
return
nil
,
err
}
}
// Persist gc size.
db
.
gcSize
,
err
=
db
.
shed
.
NewUint64Field
(
"gc-size"
)
if
err
!=
nil
{
return
nil
,
err
}
// Functions for retrieval data index.
var
(
encodeValueFunc
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
decodeValueFunc
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
)
if
o
.
MockStore
!=
nil
{
encodeValueFunc
=
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
b
:=
make
([]
byte
,
16
)
binary
.
BigEndian
.
PutUint64
(
b
[
:
8
],
fields
.
BinID
)
binary
.
BigEndian
.
PutUint64
(
b
[
8
:
16
],
uint64
(
fields
.
StoreTimestamp
))
err
=
o
.
MockStore
.
Put
(
fields
.
Address
,
fields
.
Data
)
if
err
!=
nil
{
return
nil
,
err
}
return
b
,
nil
}
decodeValueFunc
=
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
StoreTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
value
[
8
:
16
]))
e
.
BinID
=
binary
.
BigEndian
.
Uint64
(
value
[
:
8
])
e
.
Data
,
err
=
o
.
MockStore
.
Get
(
keyItem
.
Address
)
return
e
,
err
}
}
else
{
encodeValueFunc
=
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
b
:=
make
([]
byte
,
16
)
binary
.
BigEndian
.
PutUint64
(
b
[
:
8
],
fields
.
BinID
)
binary
.
BigEndian
.
PutUint64
(
b
[
8
:
16
],
uint64
(
fields
.
StoreTimestamp
))
value
=
append
(
b
,
fields
.
Data
...
)
return
value
,
nil
}
decodeValueFunc
=
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
StoreTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
value
[
8
:
16
]))
e
.
BinID
=
binary
.
BigEndian
.
Uint64
(
value
[
:
8
])
e
.
Data
=
value
[
16
:
]
return
e
,
nil
}
}
// Index storing actual chunk address, data and bin id.
db
.
retrievalDataIndex
,
err
=
db
.
shed
.
NewIndex
(
"Address->StoreTimestamp|BinID|Data"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
return
fields
.
Address
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
return
e
,
nil
},
EncodeValue
:
encodeValueFunc
,
DecodeValue
:
decodeValueFunc
,
})
if
err
!=
nil
{
return
nil
,
err
}
// Index storing access timestamp for a particular address.
// It is needed in order to update gc index keys for iteration order.
db
.
retrievalAccessIndex
,
err
=
db
.
shed
.
NewIndex
(
"Address->AccessTimestamp"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
return
fields
.
Address
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
b
:=
make
([]
byte
,
8
)
binary
.
BigEndian
.
PutUint64
(
b
,
uint64
(
fields
.
AccessTimestamp
))
return
b
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
AccessTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
value
))
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// pull index allows history and live syncing per po bin
db
.
pullIndex
,
err
=
db
.
shed
.
NewIndex
(
"PO|BinID->Hash|Tag"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
key
=
make
([]
byte
,
41
)
key
[
0
]
=
db
.
po
(
fields
.
Address
)
binary
.
BigEndian
.
PutUint64
(
key
[
1
:
9
],
fields
.
BinID
)
return
key
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
BinID
=
binary
.
BigEndian
.
Uint64
(
key
[
1
:
9
])
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
value
=
make
([]
byte
,
36
)
// 32 bytes address, 4 bytes tag
copy
(
value
,
fields
.
Address
)
if
fields
.
Tag
!=
0
{
binary
.
BigEndian
.
PutUint32
(
value
[
32
:
],
fields
.
Tag
)
}
return
value
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
value
[
:
32
]
if
len
(
value
)
>
32
{
e
.
Tag
=
binary
.
BigEndian
.
Uint32
(
value
[
32
:
])
}
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// create a vector for bin IDs
db
.
binIDs
,
err
=
db
.
shed
.
NewUint64Vector
(
"bin-ids"
)
if
err
!=
nil
{
return
nil
,
err
}
// create a pull syncing triggers used by SubscribePull function
db
.
pullTriggers
=
make
(
map
[
uint8
][]
chan
struct
{})
// push index contains as yet unsynced chunks
db
.
pushIndex
,
err
=
db
.
shed
.
NewIndex
(
"StoreTimestamp|Hash->Tags"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
key
=
make
([]
byte
,
40
)
binary
.
BigEndian
.
PutUint64
(
key
[
:
8
],
uint64
(
fields
.
StoreTimestamp
))
copy
(
key
[
8
:
],
fields
.
Address
[
:
])
return
key
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
[
8
:
]
e
.
StoreTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
key
[
:
8
]))
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
tag
:=
make
([]
byte
,
4
)
binary
.
BigEndian
.
PutUint32
(
tag
,
fields
.
Tag
)
return
tag
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
if
len
(
value
)
==
4
{
// only values with tag should be decoded
e
.
Tag
=
binary
.
BigEndian
.
Uint32
(
value
)
}
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// create a push syncing triggers used by SubscribePush function
db
.
pushTriggers
=
make
([]
chan
struct
{},
0
)
// gc index for removable chunk ordered by ascending last access time
db
.
gcIndex
,
err
=
db
.
shed
.
NewIndex
(
"AccessTimestamp|BinID|Hash->nil"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
b
:=
make
([]
byte
,
16
,
16
+
len
(
fields
.
Address
))
binary
.
BigEndian
.
PutUint64
(
b
[
:
8
],
uint64
(
fields
.
AccessTimestamp
))
binary
.
BigEndian
.
PutUint64
(
b
[
8
:
16
],
fields
.
BinID
)
key
=
append
(
b
,
fields
.
Address
...
)
return
key
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
AccessTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
key
[
:
8
]))
e
.
BinID
=
binary
.
BigEndian
.
Uint64
(
key
[
8
:
16
])
e
.
Address
=
key
[
16
:
]
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
return
nil
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// Create a index structure for storing pinned chunks and their pin counts
db
.
pinIndex
,
err
=
db
.
shed
.
NewIndex
(
"Hash->PinCounter"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
return
fields
.
Address
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
b
:=
make
([]
byte
,
8
)
binary
.
BigEndian
.
PutUint64
(
b
[
:
8
],
fields
.
PinCounter
)
return
b
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
PinCounter
=
binary
.
BigEndian
.
Uint64
(
value
[
:
8
])
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// Create a index structure for excluding pinned chunks from gcIndex
db
.
gcExcludeIndex
,
err
=
db
.
shed
.
NewIndex
(
"Hash->nil"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
return
fields
.
Address
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
return
nil
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
return
e
,
nil
},
})
if
err
!=
nil
{
return
nil
,
err
}
// start garbage collection worker
go
db
.
collectGarbageWorker
()
return
db
,
nil
}
// Close closes the underlying database.
func
(
db
*
DB
)
Close
()
(
err
error
)
{
close
(
db
.
close
)
// wait for all handlers to finish
done
:=
make
(
chan
struct
{})
go
func
()
{
db
.
updateGCWG
.
Wait
()
db
.
subscritionsWG
.
Wait
()
// wait for gc worker to
// return before closing the shed
<-
db
.
collectGarbageWorkerDone
close
(
done
)
}()
select
{
case
<-
done
:
case
<-
time
.
After
(
5
*
time
.
Second
)
:
log
.
Error
(
"localstore closed with still active goroutines"
)
// Print a full goroutine dump to debug blocking.
// TODO: use a logger to write a goroutine profile
prof
:=
pprof
.
Lookup
(
"goroutine"
)
err
=
prof
.
WriteTo
(
os
.
Stdout
,
2
)
if
err
!=
nil
{
return
err
}
}
return
db
.
shed
.
Close
()
}
// po computes the proximity order between the address
// and database base key.
func
(
db
*
DB
)
po
(
addr
chunk
.
Address
)
(
bin
uint8
)
{
return
uint8
(
chunk
.
Proximity
(
db
.
baseKey
,
addr
))
}
// DebugIndices returns the index sizes for all indexes in localstore
// the returned map keys are the index name, values are the number of elements in the index
func
(
db
*
DB
)
DebugIndices
()
(
indexInfo
map
[
string
]
int
,
err
error
)
{
indexInfo
=
make
(
map
[
string
]
int
)
for
k
,
v
:=
range
map
[
string
]
shed
.
Index
{
"retrievalDataIndex"
:
db
.
retrievalDataIndex
,
"retrievalAccessIndex"
:
db
.
retrievalAccessIndex
,
"pushIndex"
:
db
.
pushIndex
,
"pullIndex"
:
db
.
pullIndex
,
"gcIndex"
:
db
.
gcIndex
,
"gcExcludeIndex"
:
db
.
gcExcludeIndex
,
"pinIndex"
:
db
.
pinIndex
,
}
{
indexSize
,
err
:=
v
.
Count
()
if
err
!=
nil
{
return
indexInfo
,
err
}
indexInfo
[
k
]
=
indexSize
}
val
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
return
indexInfo
,
err
}
indexInfo
[
"gcSize"
]
=
int
(
val
)
return
indexInfo
,
err
}
// chunkToItem creates new Item with data provided by the Chunk.
func
chunkToItem
(
ch
chunk
.
Chunk
)
shed
.
Item
{
return
shed
.
Item
{
Address
:
ch
.
Address
(),
Data
:
ch
.
Data
(),
Tag
:
ch
.
TagID
(),
}
}
// addressToItem creates new Item with a provided address.
func
addressToItem
(
addr
chunk
.
Address
)
shed
.
Item
{
return
shed
.
Item
{
Address
:
addr
,
}
}
// addressesToItems constructs a slice of Items with only
// addresses set on them.
func
addressesToItems
(
addrs
...
chunk
.
Address
)
[]
shed
.
Item
{
items
:=
make
([]
shed
.
Item
,
len
(
addrs
))
for
i
,
addr
:=
range
addrs
{
items
[
i
]
=
shed
.
Item
{
Address
:
addr
,
}
}
return
items
}
// now is a helper function that returns a current unix timestamp
// in UTC timezone.
// It is set in the init function for usage in production, and
// optionally overridden in tests for data validation.
var
now
func
()
int64
func
init
()
{
// set the now function
now
=
func
()
(
t
int64
)
{
return
time
.
Now
()
.
UTC
()
.
UnixNano
()
}
}
// totalTimeMetric logs a message about time between provided start time
// and the time when the function is called and sends a resetting timer metric
// with provided name appended with ".total-time".
func
totalTimeMetric
(
name
string
,
start
time
.
Time
)
{
totalTime
:=
time
.
Since
(
start
)
metrics
.
GetOrRegisterResettingTimer
(
name
+
"/total-time"
,
nil
)
.
Update
(
totalTime
)
}
pkg/storage/localstore/localstore_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"fmt"
"io/ioutil"
"math/rand"
"os"
"runtime"
"sort"
"sync"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
chunktesting
"github.com/ethersphere/swarm/chunk/testing"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
func
init
()
{
// Some of the tests in localstore package rely on the same ordering of
// items uploaded or accessed compared to the ordering of items in indexes
// that contain StoreTimestamp or AccessTimestamp in keys. In tests
// where the same order is required from the database as the order
// in which chunks are put or accessed, if the StoreTimestamp or
// AccessTimestamp are the same for two or more sequential items
// their order in database will be based on the chunk address value,
// in which case the ordering of items/chunks stored in a test slice
// will not be the same. To ensure the same ordering in database on such
// indexes on windows systems, an additional short sleep is added to
// the now function.
if
runtime
.
GOOS
==
"windows"
{
setNow
(
func
()
int64
{
time
.
Sleep
(
time
.
Microsecond
)
return
time
.
Now
()
.
UTC
()
.
UnixNano
()
})
}
}
// TestDB validates if the chunk can be uploaded and
// correctly retrieved.
func
TestDB
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got address %x, want %x"
,
got
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got data %x, want %x"
,
got
.
Data
(),
ch
.
Data
())
}
}
// TestDB_updateGCSem tests maxParallelUpdateGC limit.
// This test temporary sets the limit to a low number,
// makes updateGC function execution time longer by
// setting a custom testHookUpdateGC function with a sleep
// and a count current and maximal number of goroutines.
func
TestDB_updateGCSem
(
t
*
testing
.
T
)
{
updateGCSleep
:=
time
.
Second
var
count
int
var
max
int
var
mu
sync
.
Mutex
defer
setTestHookUpdateGC
(
func
()
{
mu
.
Lock
()
// add to the count of current goroutines
count
++
if
count
>
max
{
// set maximal detected numbers of goroutines
max
=
count
}
mu
.
Unlock
()
// wait for some time to ensure multiple parallel goroutines
time
.
Sleep
(
updateGCSleep
)
mu
.
Lock
()
count
--
mu
.
Unlock
()
})()
defer
func
(
m
int
)
{
maxParallelUpdateGC
=
m
}(
maxParallelUpdateGC
)
maxParallelUpdateGC
=
3
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// get more chunks then maxParallelUpdateGC
// in time shorter then updateGCSleep
for
i
:=
0
;
i
<
5
;
i
++
{
_
,
err
=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
if
max
!=
maxParallelUpdateGC
{
t
.
Errorf
(
"got max %v, want %v"
,
max
,
maxParallelUpdateGC
)
}
}
// newTestDB is a helper function that constructs a
// temporary database and returns a cleanup function that must
// be called to remove the data.
func
newTestDB
(
t
testing
.
TB
,
o
*
Options
)
(
db
*
DB
,
cleanupFunc
func
())
{
t
.
Helper
()
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
cleanupFunc
=
func
()
{
os
.
RemoveAll
(
dir
)
}
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
db
,
err
=
New
(
dir
,
baseKey
,
o
)
if
err
!=
nil
{
cleanupFunc
()
t
.
Fatal
(
err
)
}
cleanupFunc
=
func
()
{
err
:=
db
.
Close
()
if
err
!=
nil
{
t
.
Error
(
err
)
}
os
.
RemoveAll
(
dir
)
}
return
db
,
cleanupFunc
}
var
(
generateTestRandomChunk
=
chunktesting
.
GenerateTestRandomChunk
generateTestRandomChunks
=
chunktesting
.
GenerateTestRandomChunks
)
// chunkAddresses return chunk addresses of provided chunks.
func
chunkAddresses
(
chunks
[]
chunk
.
Chunk
)
[]
chunk
.
Address
{
addrs
:=
make
([]
chunk
.
Address
,
len
(
chunks
))
for
i
,
ch
:=
range
chunks
{
addrs
[
i
]
=
ch
.
Address
()
}
return
addrs
}
// Standard test cases to validate multi chunk operations.
var
multiChunkTestCases
=
[]
struct
{
name
string
count
int
}{
{
name
:
"one"
,
count
:
1
,
},
{
name
:
"two"
,
count
:
2
,
},
{
name
:
"eight"
,
count
:
8
,
},
{
name
:
"hundred"
,
count
:
100
,
},
{
name
:
"thousand"
,
count
:
1000
,
},
}
// TestGenerateTestRandomChunk validates that
// generateTestRandomChunk returns random data by comparing
// two generated chunks.
func
TestGenerateTestRandomChunk
(
t
*
testing
.
T
)
{
c1
:=
generateTestRandomChunk
()
c2
:=
generateTestRandomChunk
()
addrLen
:=
len
(
c1
.
Address
())
if
addrLen
!=
32
{
t
.
Errorf
(
"first chunk address length %v, want %v"
,
addrLen
,
32
)
}
dataLen
:=
len
(
c1
.
Data
())
if
dataLen
!=
chunk
.
DefaultSize
{
t
.
Errorf
(
"first chunk data length %v, want %v"
,
dataLen
,
chunk
.
DefaultSize
)
}
addrLen
=
len
(
c2
.
Address
())
if
addrLen
!=
32
{
t
.
Errorf
(
"second chunk address length %v, want %v"
,
addrLen
,
32
)
}
dataLen
=
len
(
c2
.
Data
())
if
dataLen
!=
chunk
.
DefaultSize
{
t
.
Errorf
(
"second chunk data length %v, want %v"
,
dataLen
,
chunk
.
DefaultSize
)
}
if
bytes
.
Equal
(
c1
.
Address
(),
c2
.
Address
())
{
t
.
Error
(
"fake chunks addresses do not differ"
)
}
if
bytes
.
Equal
(
c1
.
Data
(),
c2
.
Data
())
{
t
.
Error
(
"fake chunks data bytes do not differ"
)
}
}
// newRetrieveIndexesTest returns a test function that validates if the right
// chunk values are in the retrieval indexes
func
newRetrieveIndexesTest
(
db
*
DB
,
chunk
chunk
.
Chunk
,
storeTimestamp
,
accessTimestamp
int64
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
item
,
err
:=
db
.
retrievalDataIndex
.
Get
(
addressToItem
(
chunk
.
Address
()))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
validateItem
(
t
,
item
,
chunk
.
Address
(),
chunk
.
Data
(),
storeTimestamp
,
0
)
// access index should not be set
wantErr
:=
leveldb
.
ErrNotFound
_
,
err
=
db
.
retrievalAccessIndex
.
Get
(
addressToItem
(
chunk
.
Address
()))
if
err
!=
wantErr
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantErr
)
}
}
}
// newRetrieveIndexesTestWithAccess returns a test function that validates if the right
// chunk values are in the retrieval indexes when access time must be stored.
func
newRetrieveIndexesTestWithAccess
(
db
*
DB
,
ch
chunk
.
Chunk
,
storeTimestamp
,
accessTimestamp
int64
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
item
,
err
:=
db
.
retrievalDataIndex
.
Get
(
addressToItem
(
ch
.
Address
()))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
validateItem
(
t
,
item
,
ch
.
Address
(),
ch
.
Data
(),
storeTimestamp
,
0
)
if
accessTimestamp
>
0
{
item
,
err
=
db
.
retrievalAccessIndex
.
Get
(
addressToItem
(
ch
.
Address
()))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
validateItem
(
t
,
item
,
ch
.
Address
(),
nil
,
0
,
accessTimestamp
)
}
}
}
// newPullIndexTest returns a test function that validates if the right
// chunk values are in the pull index.
func
newPullIndexTest
(
db
*
DB
,
ch
chunk
.
Chunk
,
binID
uint64
,
wantError
error
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
item
,
err
:=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
binID
,
})
if
err
!=
wantError
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantError
)
}
if
err
==
nil
{
validateItem
(
t
,
item
,
ch
.
Address
(),
nil
,
0
,
0
)
}
}
}
// newPushIndexTest returns a test function that validates if the right
// chunk values are in the push index.
func
newPushIndexTest
(
db
*
DB
,
ch
chunk
.
Chunk
,
storeTimestamp
int64
,
wantError
error
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
item
,
err
:=
db
.
pushIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
StoreTimestamp
:
storeTimestamp
,
})
if
err
!=
wantError
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantError
)
}
if
err
==
nil
{
validateItem
(
t
,
item
,
ch
.
Address
(),
nil
,
storeTimestamp
,
0
)
}
}
}
// newGCIndexTest returns a test function that validates if the right
// chunk values are in the GC index.
func
newGCIndexTest
(
db
*
DB
,
chunk
chunk
.
Chunk
,
storeTimestamp
,
accessTimestamp
int64
,
binID
uint64
,
wantError
error
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
item
,
err
:=
db
.
gcIndex
.
Get
(
shed
.
Item
{
Address
:
chunk
.
Address
(),
BinID
:
binID
,
AccessTimestamp
:
accessTimestamp
,
})
if
err
!=
wantError
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantError
)
}
if
err
==
nil
{
validateItem
(
t
,
item
,
chunk
.
Address
(),
nil
,
0
,
accessTimestamp
)
}
}
}
// newItemsCountTest returns a test function that validates if
// an index contains expected number of key/value pairs.
func
newItemsCountTest
(
i
shed
.
Index
,
want
int
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
var
c
int
err
:=
i
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
c
++
return
},
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
c
!=
want
{
t
.
Errorf
(
"got %v items in index, want %v"
,
c
,
want
)
}
}
}
// newIndexGCSizeTest retruns a test function that validates if DB.gcSize
// value is the same as the number of items in DB.gcIndex.
func
newIndexGCSizeTest
(
db
*
DB
)
func
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
)
{
t
.
Helper
()
var
want
uint64
err
:=
db
.
gcIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
want
++
return
},
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
got
,
err
:=
db
.
gcSize
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
got
!=
want
{
t
.
Errorf
(
"got gc size %v, want %v"
,
got
,
want
)
}
}
}
// testIndexChunk embeds storageChunk with additional data that is stored
// in database. It is used for index values validations.
type
testIndexChunk
struct
{
chunk
.
Chunk
binID
uint64
}
// testItemsOrder tests the order of chunks in the index. If sortFunc is not nil,
// chunks will be sorted with it before validation.
func
testItemsOrder
(
t
*
testing
.
T
,
i
shed
.
Index
,
chunks
[]
testIndexChunk
,
sortFunc
func
(
i
,
j
int
)
(
less
bool
))
{
t
.
Helper
()
newItemsCountTest
(
i
,
len
(
chunks
))(
t
)
if
sortFunc
!=
nil
{
sort
.
Slice
(
chunks
,
sortFunc
)
}
var
cursor
int
err
:=
i
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
want
:=
chunks
[
cursor
]
.
Address
()
got
:=
item
.
Address
if
!
bytes
.
Equal
(
got
,
want
)
{
return
true
,
fmt
.
Errorf
(
"got address %x at position %v, want %x"
,
got
,
cursor
,
want
)
}
cursor
++
return
false
,
nil
},
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
// validateItem is a helper function that checks Item values.
func
validateItem
(
t
*
testing
.
T
,
item
shed
.
Item
,
address
,
data
[]
byte
,
storeTimestamp
,
accessTimestamp
int64
)
{
t
.
Helper
()
if
!
bytes
.
Equal
(
item
.
Address
,
address
)
{
t
.
Errorf
(
"got item address %x, want %x"
,
item
.
Address
,
address
)
}
if
!
bytes
.
Equal
(
item
.
Data
,
data
)
{
t
.
Errorf
(
"got item data %x, want %x"
,
item
.
Data
,
data
)
}
if
item
.
StoreTimestamp
!=
storeTimestamp
{
t
.
Errorf
(
"got item store timestamp %v, want %v"
,
item
.
StoreTimestamp
,
storeTimestamp
)
}
if
item
.
AccessTimestamp
!=
accessTimestamp
{
t
.
Errorf
(
"got item access timestamp %v, want %v"
,
item
.
AccessTimestamp
,
accessTimestamp
)
}
}
// setNow replaces now function and
// returns a function that will reset it to the
// value before the change.
func
setNow
(
f
func
()
int64
)
(
reset
func
())
{
current
:=
now
reset
=
func
()
{
now
=
current
}
now
=
f
return
reset
}
// TestSetNow tests if setNow function changes now function
// correctly and if its reset function resets the original function.
func
TestSetNow
(
t
*
testing
.
T
)
{
// set the current function after the test finishes
defer
func
(
f
func
()
int64
)
{
now
=
f
}(
now
)
// expected value for the unchanged function
var
original
int64
=
1
// expected value for the changed function
var
changed
int64
=
2
// define the original (unchanged) functions
now
=
func
()
int64
{
return
original
}
// get the time
got
:=
now
()
// test if got variable is set correctly
if
got
!=
original
{
t
.
Errorf
(
"got now value %v, want %v"
,
got
,
original
)
}
// set the new function
reset
:=
setNow
(
func
()
int64
{
return
changed
})
// get the time
got
=
now
()
// test if got variable is set correctly to changed value
if
got
!=
changed
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
changed
)
}
// set the function to the original one
reset
()
// get the time
got
=
now
()
// test if got variable is set correctly to original value
if
got
!=
original
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
original
)
}
}
func
testIndexCounts
(
t
*
testing
.
T
,
pushIndex
,
pullIndex
,
gcIndex
,
gcExcludeIndex
,
pinIndex
,
retrievalDataIndex
,
retrievalAccessIndex
int
,
indexInfo
map
[
string
]
int
)
{
t
.
Helper
()
if
indexInfo
[
"pushIndex"
]
!=
pushIndex
{
t
.
Fatalf
(
"pushIndex count mismatch. got %d want %d"
,
indexInfo
[
"pushIndex"
],
pushIndex
)
}
if
indexInfo
[
"pullIndex"
]
!=
pullIndex
{
t
.
Fatalf
(
"pullIndex count mismatch. got %d want %d"
,
indexInfo
[
"pullIndex"
],
pullIndex
)
}
if
indexInfo
[
"gcIndex"
]
!=
gcIndex
{
t
.
Fatalf
(
"gcIndex count mismatch. got %d want %d"
,
indexInfo
[
"gcIndex"
],
gcIndex
)
}
if
indexInfo
[
"gcExcludeIndex"
]
!=
gcExcludeIndex
{
t
.
Fatalf
(
"gcExcludeIndex count mismatch. got %d want %d"
,
indexInfo
[
"gcExcludeIndex"
],
gcExcludeIndex
)
}
if
indexInfo
[
"pinIndex"
]
!=
pinIndex
{
t
.
Fatalf
(
"pinIndex count mismatch. got %d want %d"
,
indexInfo
[
"pinIndex"
],
pinIndex
)
}
if
indexInfo
[
"retrievalDataIndex"
]
!=
retrievalDataIndex
{
t
.
Fatalf
(
"retrievalDataIndex count mismatch. got %d want %d"
,
indexInfo
[
"retrievalDataIndex"
],
retrievalDataIndex
)
}
if
indexInfo
[
"retrievalAccessIndex"
]
!=
retrievalAccessIndex
{
t
.
Fatalf
(
"retrievalAccessIndex count mismatch. got %d want %d"
,
indexInfo
[
"retrievalAccessIndex"
],
retrievalAccessIndex
)
}
}
// TestDBDebugIndexes tests that the index counts are correct for the
// index debug function
func
TestDBDebugIndexes
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
uploadTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
uploadTimestamp
})()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
indexCounts
,
err
:=
db
.
DebugIndices
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// for reference: testIndexCounts(t *testing.T, pushIndex, pullIndex, gcIndex, gcExcludeIndex, pinIndex, retrievalDataIndex, retrievalAccessIndex int, indexInfo map[string]int)
testIndexCounts
(
t
,
1
,
1
,
0
,
0
,
0
,
1
,
0
,
indexCounts
)
// set the chunk for pinning and expect the index count to grow
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetPin
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
indexCounts
,
err
=
db
.
DebugIndices
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// assert that there's a pin and gc exclude entry now
testIndexCounts
(
t
,
1
,
1
,
0
,
1
,
1
,
1
,
0
,
indexCounts
)
// set the chunk as accessed and expect the access index to grow
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetAccess
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
indexCounts
,
err
=
db
.
DebugIndices
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// assert that there's a pin and gc exclude entry now
testIndexCounts
(
t
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
indexCounts
)
}
pkg/storage/localstore/migration.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The Swarm Authors
// This file is part of the Swarm library.
//
// The Swarm library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Swarm library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Swarm library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"encoding/binary"
"errors"
"fmt"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/log"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
var
errMissingCurrentSchema
=
errors
.
New
(
"could not find current db schema"
)
var
errMissingTargetSchema
=
errors
.
New
(
"could not find target db schema"
)
type
migration
struct
{
name
string
// name of the schema
fn
func
(
db
*
DB
)
error
// the migration function that needs to be performed in order to get to the current schema name
}
// schemaMigrations contains an ordered list of the database schemes, that is
// in order to run data migrations in the correct sequence
var
schemaMigrations
=
[]
migration
{
{
name
:
DbSchemaPurity
,
fn
:
func
(
db
*
DB
)
error
{
return
nil
}},
{
name
:
DbSchemaHalloween
,
fn
:
func
(
db
*
DB
)
error
{
return
nil
}},
{
name
:
DbSchemaSanctuary
,
fn
:
func
(
db
*
DB
)
error
{
return
nil
}},
{
name
:
DbSchemaDiwali
,
fn
:
migrateSanctuary
},
}
func
(
db
*
DB
)
migrate
(
schemaName
string
)
error
{
migrations
,
err
:=
getMigrations
(
schemaName
,
DbSchemaCurrent
,
schemaMigrations
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error getting migrations for current schema (%s): %v"
,
schemaName
,
err
)
}
// no migrations to run
if
migrations
==
nil
{
return
nil
}
log
.
Info
(
"need to run data migrations on localstore"
,
"numMigrations"
,
len
(
migrations
),
"schemaName"
,
schemaName
)
for
i
:=
0
;
i
<
len
(
migrations
);
i
++
{
err
:=
migrations
[
i
]
.
fn
(
db
)
if
err
!=
nil
{
return
err
}
err
=
db
.
schemaName
.
Put
(
migrations
[
i
]
.
name
)
// put the name of the current schema
if
err
!=
nil
{
return
err
}
schemaName
,
err
=
db
.
schemaName
.
Get
()
if
err
!=
nil
{
return
err
}
log
.
Info
(
"successfully ran migration"
,
"migrationId"
,
i
,
"currentSchema"
,
schemaName
)
}
return
nil
}
// getMigrations returns an ordered list of migrations that need be executed
// with no errors in order to bring the localstore to the most up-to-date
// schema definition
func
getMigrations
(
currentSchema
,
targetSchema
string
,
allSchemeMigrations
[]
migration
)
(
migrations
[]
migration
,
err
error
)
{
foundCurrent
:=
false
foundTarget
:=
false
if
currentSchema
==
DbSchemaCurrent
{
return
nil
,
nil
}
for
i
,
v
:=
range
allSchemeMigrations
{
switch
v
.
name
{
case
currentSchema
:
if
foundCurrent
{
return
nil
,
errors
.
New
(
"found schema name for the second time when looking for migrations"
)
}
foundCurrent
=
true
log
.
Info
(
"found current localstore schema"
,
"currentSchema"
,
currentSchema
,
"migrateTo"
,
DbSchemaCurrent
,
"total migrations"
,
len
(
allSchemeMigrations
)
-
i
)
continue
// current schema migration should not be executed (already has been when schema was migrated to)
case
targetSchema
:
foundTarget
=
true
}
if
foundCurrent
{
migrations
=
append
(
migrations
,
v
)
}
}
if
!
foundCurrent
{
return
nil
,
errMissingCurrentSchema
}
if
!
foundTarget
{
return
nil
,
errMissingTargetSchema
}
return
migrations
,
nil
}
// this function migrates Sanctuary schema to the Diwali schema
func
migrateSanctuary
(
db
*
DB
)
error
{
// just rename the pull index
renamed
,
err
:=
db
.
shed
.
RenameIndex
(
"PO|BinID->Hash"
,
"PO|BinID->Hash|Tag"
)
if
err
!=
nil
{
return
err
}
if
!
renamed
{
return
errors
.
New
(
"pull index was not successfully renamed"
)
}
if
db
.
tags
==
nil
{
return
errors
.
New
(
"had an error accessing the tags object"
)
}
batch
:=
new
(
leveldb
.
Batch
)
db
.
batchMu
.
Lock
()
defer
db
.
batchMu
.
Unlock
()
// since pullIndex points to the Tag value, we should eliminate possible
// pushIndex leak due to items that were used by previous pull sync tag
// increment logic. we need to build the index first since db object is
// still not initialised at this stage
db
.
pushIndex
,
err
=
db
.
shed
.
NewIndex
(
"StoreTimestamp|Hash->Tags"
,
shed
.
IndexFuncs
{
EncodeKey
:
func
(
fields
shed
.
Item
)
(
key
[]
byte
,
err
error
)
{
key
=
make
([]
byte
,
40
)
binary
.
BigEndian
.
PutUint64
(
key
[
:
8
],
uint64
(
fields
.
StoreTimestamp
))
copy
(
key
[
8
:
],
fields
.
Address
[
:
])
return
key
,
nil
},
DecodeKey
:
func
(
key
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
e
.
Address
=
key
[
8
:
]
e
.
StoreTimestamp
=
int64
(
binary
.
BigEndian
.
Uint64
(
key
[
:
8
]))
return
e
,
nil
},
EncodeValue
:
func
(
fields
shed
.
Item
)
(
value
[]
byte
,
err
error
)
{
tag
:=
make
([]
byte
,
4
)
binary
.
BigEndian
.
PutUint32
(
tag
,
fields
.
Tag
)
return
tag
,
nil
},
DecodeValue
:
func
(
keyItem
shed
.
Item
,
value
[]
byte
)
(
e
shed
.
Item
,
err
error
)
{
if
value
!=
nil
{
e
.
Tag
=
binary
.
BigEndian
.
Uint32
(
value
)
}
return
e
,
nil
},
})
if
err
!=
nil
{
return
err
}
err
=
db
.
pushIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
tag
,
err
:=
db
.
tags
.
Get
(
item
.
Tag
)
if
err
!=
nil
{
if
err
==
chunk
.
TagNotFoundErr
{
return
false
,
nil
}
return
true
,
err
}
// anonymous tags should no longer appear in pushIndex
if
tag
!=
nil
&&
tag
.
Anonymous
{
err
=
db
.
pushIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
true
,
nil
}
}
return
false
,
nil
},
nil
)
if
err
!=
nil
{
return
err
}
return
db
.
shed
.
WriteBatch
(
batch
)
}
pkg/storage/localstore/migration_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The Swarm Authors
// This file is part of the Swarm library.
//
// The Swarm library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Swarm library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Swarm library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"path"
"strings"
"testing"
"github.com/ethersphere/swarm/chunk"
)
func
TestOneMigration
(
t
*
testing
.
T
)
{
defer
func
(
v
[]
migration
,
s
string
)
{
schemaMigrations
=
v
DbSchemaCurrent
=
s
}(
schemaMigrations
,
DbSchemaCurrent
)
DbSchemaCurrent
=
DbSchemaSanctuary
ran
:=
false
shouldNotRun
:=
false
schemaMigrations
=
[]
migration
{
{
name
:
DbSchemaSanctuary
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
// this should not be executed
return
nil
}},
{
name
:
DbSchemaDiwali
,
fn
:
func
(
db
*
DB
)
error
{
ran
=
true
return
nil
}},
}
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
dir
)
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
// start the fresh localstore with the sanctuary schema name
db
,
err
:=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
DbSchemaCurrent
=
DbSchemaDiwali
// start the existing localstore and expect the migration to run
db
,
err
=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
schemaName
,
err
:=
db
.
schemaName
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
schemaName
!=
DbSchemaDiwali
{
t
.
Errorf
(
"schema name mismatch. got '%s', want '%s'"
,
schemaName
,
DbSchemaDiwali
)
}
if
!
ran
{
t
.
Errorf
(
"expected migration did not run"
)
}
if
shouldNotRun
{
t
.
Errorf
(
"migration ran but shouldnt have"
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Error
(
err
)
}
}
func
TestManyMigrations
(
t
*
testing
.
T
)
{
defer
func
(
v
[]
migration
,
s
string
)
{
schemaMigrations
=
v
DbSchemaCurrent
=
s
}(
schemaMigrations
,
DbSchemaCurrent
)
DbSchemaCurrent
=
DbSchemaSanctuary
shouldNotRun
:=
false
executionOrder
:=
[]
int
{
-
1
,
-
1
,
-
1
,
-
1
}
schemaMigrations
=
[]
migration
{
{
name
:
DbSchemaSanctuary
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
// this should not be executed
return
nil
}},
{
name
:
DbSchemaDiwali
,
fn
:
func
(
db
*
DB
)
error
{
executionOrder
[
0
]
=
0
return
nil
}},
{
name
:
"coconut"
,
fn
:
func
(
db
*
DB
)
error
{
executionOrder
[
1
]
=
1
return
nil
}},
{
name
:
"mango"
,
fn
:
func
(
db
*
DB
)
error
{
executionOrder
[
2
]
=
2
return
nil
}},
{
name
:
"salvation"
,
fn
:
func
(
db
*
DB
)
error
{
executionOrder
[
3
]
=
3
return
nil
}},
}
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
dir
)
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
// start the fresh localstore with the sanctuary schema name
db
,
err
:=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
DbSchemaCurrent
=
"salvation"
// start the existing localstore and expect the migration to run
db
,
err
=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
schemaName
,
err
:=
db
.
schemaName
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
schemaName
!=
"salvation"
{
t
.
Errorf
(
"schema name mismatch. got '%s', want '%s'"
,
schemaName
,
"salvation"
)
}
if
shouldNotRun
{
t
.
Errorf
(
"migration ran but shouldnt have"
)
}
for
i
,
v
:=
range
executionOrder
{
if
i
!=
v
&&
i
!=
len
(
executionOrder
)
-
1
{
t
.
Errorf
(
"migration did not run in sequence, slot %d value %d"
,
i
,
v
)
}
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Error
(
err
)
}
}
// TestMigrationFailFrom checks that local store boot should fail when the schema we're migrating from cannot be found
func
TestMigrationFailFrom
(
t
*
testing
.
T
)
{
defer
func
(
v
[]
migration
,
s
string
)
{
schemaMigrations
=
v
DbSchemaCurrent
=
s
}(
schemaMigrations
,
DbSchemaCurrent
)
DbSchemaCurrent
=
"koo-koo-schema"
shouldNotRun
:=
false
schemaMigrations
=
[]
migration
{
{
name
:
"langur"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
{
name
:
"coconut"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
{
name
:
"chutney"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
}
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
dir
)
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
// start the fresh localstore with the sanctuary schema name
db
,
err
:=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
DbSchemaCurrent
=
"foo"
// start the existing localstore and expect the migration to run
_
,
err
=
New
(
dir
,
baseKey
,
nil
)
if
!
strings
.
Contains
(
err
.
Error
(),
errMissingCurrentSchema
.
Error
())
{
t
.
Fatalf
(
"expected errCannotFindSchema but got %v"
,
err
)
}
if
shouldNotRun
{
t
.
Errorf
(
"migration ran but shouldnt have"
)
}
}
// TestMigrationFailTo checks that local store boot should fail when the schema we're migrating to cannot be found
func
TestMigrationFailTo
(
t
*
testing
.
T
)
{
defer
func
(
v
[]
migration
,
s
string
)
{
schemaMigrations
=
v
DbSchemaCurrent
=
s
}(
schemaMigrations
,
DbSchemaCurrent
)
DbSchemaCurrent
=
"langur"
shouldNotRun
:=
false
schemaMigrations
=
[]
migration
{
{
name
:
"langur"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
{
name
:
"coconut"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
{
name
:
"chutney"
,
fn
:
func
(
db
*
DB
)
error
{
shouldNotRun
=
true
return
nil
}},
}
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
dir
)
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
// start the fresh localstore with the sanctuary schema name
db
,
err
:=
New
(
dir
,
baseKey
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
DbSchemaCurrent
=
"foo"
// start the existing localstore and expect the migration to run
_
,
err
=
New
(
dir
,
baseKey
,
nil
)
if
!
strings
.
Contains
(
err
.
Error
(),
errMissingTargetSchema
.
Error
())
{
t
.
Fatalf
(
"expected errMissingTargetSchema but got %v"
,
err
)
}
if
shouldNotRun
{
t
.
Errorf
(
"migration ran but shouldnt have"
)
}
}
// TestMigrateSanctuaryFixture migrates an actual Sanctuary localstore
// to the most recent schema.
func
TestMigrateSanctuaryFixture
(
t
*
testing
.
T
)
{
tmpdir
,
err
:=
ioutil
.
TempDir
(
""
,
"localstore-test"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
tmpdir
)
dir
:=
path
.
Join
(
"."
,
"testdata"
,
"sanctuary"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
files
,
err
:=
ioutil
.
ReadDir
(
dir
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
for
_
,
f
:=
range
files
{
err
=
copyFileContents
(
path
.
Join
(
dir
,
f
.
Name
()),
path
.
Join
(
tmpdir
,
f
.
Name
()))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
baseKey
:=
make
([]
byte
,
32
)
if
_
,
err
:=
rand
.
Read
(
baseKey
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
// start localstore with the copied fixture
db
,
err
:=
New
(
tmpdir
,
baseKey
,
&
Options
{
Tags
:
chunk
.
NewTags
()})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
schemaName
,
err
:=
db
.
schemaName
.
Get
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
schemaName
!=
DbSchemaCurrent
{
t
.
Fatalf
(
"schema name mismatch, want '%s' got '%s'"
,
DbSchemaCurrent
,
schemaName
)
}
err
=
db
.
Close
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
copyFileContents
(
src
,
dst
string
)
(
err
error
)
{
in
,
err
:=
os
.
Open
(
src
)
if
err
!=
nil
{
return
err
}
defer
in
.
Close
()
out
,
err
:=
os
.
Create
(
dst
)
if
err
!=
nil
{
return
err
}
defer
out
.
Close
()
if
_
,
err
=
io
.
Copy
(
out
,
in
);
err
!=
nil
{
return
err
}
return
out
.
Sync
()
}
pkg/storage/localstore/mode_get.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"fmt"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
// Get returns a chunk from the database. If the chunk is
// not found chunk.ErrChunkNotFound will be returned.
// All required indexes will be updated required by the
// Getter Mode. Get is required to implement chunk.Store
// interface.
func
(
db
*
DB
)
Get
(
ctx
context
.
Context
,
mode
chunk
.
ModeGet
,
addr
chunk
.
Address
)
(
ch
chunk
.
Chunk
,
err
error
)
{
metricName
:=
fmt
.
Sprintf
(
"localstore/Get/%s"
,
mode
)
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
defer
func
()
{
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
}()
out
,
err
:=
db
.
get
(
mode
,
addr
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
return
nil
,
chunk
.
ErrChunkNotFound
}
return
nil
,
err
}
return
chunk
.
NewChunk
(
out
.
Address
,
out
.
Data
)
.
WithPinCounter
(
out
.
PinCounter
),
nil
}
// get returns Item from the retrieval index
// and updates other indexes.
func
(
db
*
DB
)
get
(
mode
chunk
.
ModeGet
,
addr
chunk
.
Address
)
(
out
shed
.
Item
,
err
error
)
{
item
:=
addressToItem
(
addr
)
out
,
err
=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
return
out
,
err
}
switch
mode
{
// update the access timestamp and gc index
case
chunk
.
ModeGetRequest
:
db
.
updateGCItems
(
out
)
case
chunk
.
ModeGetPin
:
pinnedItem
,
err
:=
db
.
pinIndex
.
Get
(
item
)
if
err
!=
nil
{
return
out
,
err
}
return
pinnedItem
,
nil
// no updates to indexes
case
chunk
.
ModeGetSync
:
case
chunk
.
ModeGetLookup
:
default
:
return
out
,
ErrInvalidMode
}
return
out
,
nil
}
// updateGCItems is called when ModeGetRequest is used
// for Get or GetMulti to update access time and gc indexes
// for all returned chunks.
func
(
db
*
DB
)
updateGCItems
(
items
...
shed
.
Item
)
{
if
db
.
updateGCSem
!=
nil
{
// wait before creating new goroutines
// if updateGCSem buffer id full
db
.
updateGCSem
<-
struct
{}{}
}
db
.
updateGCWG
.
Add
(
1
)
go
func
()
{
defer
db
.
updateGCWG
.
Done
()
if
db
.
updateGCSem
!=
nil
{
// free a spot in updateGCSem buffer
// for a new goroutine
defer
func
()
{
<-
db
.
updateGCSem
}()
}
metricName
:=
"localstore/updateGC"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
for
_
,
item
:=
range
items
{
err
:=
db
.
updateGC
(
item
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
log
.
Error
(
"localstore update gc"
,
"err"
,
err
)
}
}
// if gc update hook is defined, call it
if
testHookUpdateGC
!=
nil
{
testHookUpdateGC
()
}
}()
}
// updateGC updates garbage collection index for
// a single item. Provided item is expected to have
// only Address and Data fields with non zero values,
// which is ensured by the get function.
func
(
db
*
DB
)
updateGC
(
item
shed
.
Item
)
(
err
error
)
{
db
.
batchMu
.
Lock
()
defer
db
.
batchMu
.
Unlock
()
batch
:=
new
(
leveldb
.
Batch
)
// update accessTimeStamp in retrieve, gc
i
,
err
:=
db
.
retrievalAccessIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
AccessTimestamp
=
i
.
AccessTimestamp
case
leveldb
.
ErrNotFound
:
// no chunk accesses
default
:
return
err
}
if
item
.
AccessTimestamp
==
0
{
// chunk is not yet synced
// do not add it to the gc index
return
nil
}
// delete current entry from the gc index
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
// update access timestamp
item
.
AccessTimestamp
=
now
()
// update retrieve access index
err
=
db
.
retrievalAccessIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
// add new entry to gc index
err
=
db
.
gcIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
return
db
.
shed
.
WriteBatch
(
batch
)
}
// testHookUpdateGC is a hook that can provide
// information when a garbage collection index is updated.
var
testHookUpdateGC
func
()
pkg/storage/localstore/mode_get_multi.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The Swarm Authors
// This file is part of the Swarm library.
//
// The Swarm library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Swarm library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Swarm library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"fmt"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
// GetMulti returns chunks from the database. If one of the chunks is not found
// chunk.ErrChunkNotFound will be returned. All required indexes will be updated
// required by the Getter Mode. GetMulti is required to implement chunk.Store
// interface.
func
(
db
*
DB
)
GetMulti
(
ctx
context
.
Context
,
mode
chunk
.
ModeGet
,
addrs
...
chunk
.
Address
)
(
chunks
[]
chunk
.
Chunk
,
err
error
)
{
metricName
:=
fmt
.
Sprintf
(
"localstore/GetMulti/%s"
,
mode
)
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
defer
func
()
{
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
}()
out
,
err
:=
db
.
getMulti
(
mode
,
addrs
...
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
return
nil
,
chunk
.
ErrChunkNotFound
}
return
nil
,
err
}
chunks
=
make
([]
chunk
.
Chunk
,
len
(
out
))
for
i
,
ch
:=
range
out
{
chunks
[
i
]
=
chunk
.
NewChunk
(
ch
.
Address
,
ch
.
Data
)
.
WithPinCounter
(
ch
.
PinCounter
)
}
return
chunks
,
nil
}
// getMulti returns Items from the retrieval index
// and updates other indexes.
func
(
db
*
DB
)
getMulti
(
mode
chunk
.
ModeGet
,
addrs
...
chunk
.
Address
)
(
out
[]
shed
.
Item
,
err
error
)
{
out
=
make
([]
shed
.
Item
,
len
(
addrs
))
for
i
,
addr
:=
range
addrs
{
out
[
i
]
.
Address
=
addr
}
err
=
db
.
retrievalDataIndex
.
Fill
(
out
)
if
err
!=
nil
{
return
nil
,
err
}
switch
mode
{
// update the access timestamp and gc index
case
chunk
.
ModeGetRequest
:
db
.
updateGCItems
(
out
...
)
case
chunk
.
ModeGetPin
:
err
:=
db
.
pinIndex
.
Fill
(
out
)
if
err
!=
nil
{
return
nil
,
err
}
// no updates to indexes
case
chunk
.
ModeGetSync
:
case
chunk
.
ModeGetLookup
:
default
:
return
out
,
ErrInvalidMode
}
return
out
,
nil
}
pkg/storage/localstore/mode_get_multi_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The Swarm Authors
// This file is part of the Swarm library.
//
// The Swarm library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Swarm library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Swarm library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"reflect"
"testing"
"github.com/ethersphere/swarm/chunk"
)
// TestModeGetMulti stores chunks and validates that GetMulti
// is returning them correctly.
func
TestModeGetMulti
(
t
*
testing
.
T
)
{
const
chunkCount
=
10
for
_
,
mode
:=
range
[]
chunk
.
ModeGet
{
chunk
.
ModeGetRequest
,
chunk
.
ModeGetSync
,
chunk
.
ModeGetLookup
,
chunk
.
ModeGetPin
,
}
{
t
.
Run
(
mode
.
String
(),
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
generateTestRandomChunks
(
chunkCount
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
mode
==
chunk
.
ModeGetPin
{
// pin chunks so that it is not returned as not found by pinIndex
for
i
,
ch
:=
range
chunks
{
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetPin
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
[
i
]
=
ch
.
WithPinCounter
(
1
)
}
}
addrs
:=
chunkAddresses
(
chunks
)
got
,
err
:=
db
.
GetMulti
(
context
.
Background
(),
mode
,
addrs
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
if
!
reflect
.
DeepEqual
(
got
[
i
],
chunks
[
i
])
{
t
.
Errorf
(
"got %v chunk %v, want %v"
,
i
,
got
[
i
],
chunks
[
i
])
}
}
missingChunk
:=
generateTestRandomChunk
()
want
:=
chunk
.
ErrChunkNotFound
_
,
err
=
db
.
GetMulti
(
context
.
Background
(),
mode
,
append
(
addrs
,
missingChunk
.
Address
())
...
)
if
err
!=
want
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
want
)
}
})
}
}
pkg/storage/localstore/mode_get_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
)
// TestModeGetRequest validates ModeGetRequest index values on the provided DB.
func
TestModeGetRequest
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
uploadTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
uploadTimestamp
})()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// set update gc test hook to signal when
// update gc goroutine is done by sending to
// testHookUpdateGCChan channel, which is
// used to wait for garbage colletion index
// changes
testHookUpdateGCChan
:=
make
(
chan
struct
{})
defer
setTestHookUpdateGC
(
func
()
{
testHookUpdateGCChan
<-
struct
{}{}
})()
t
.
Run
(
"get unsynced"
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
.
Data
(),
ch
.
Data
())
}
t
.
Run
(
"retrieve indexes"
,
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
uploadTimestamp
,
0
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
0
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
// set chunk to synced state
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
t
.
Run
(
"first get"
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
.
Data
(),
ch
.
Data
())
}
t
.
Run
(
"retrieve indexes"
,
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
uploadTimestamp
,
uploadTimestamp
))
t
.
Run
(
"gc index"
,
newGCIndexTest
(
db
,
ch
,
uploadTimestamp
,
uploadTimestamp
,
1
,
nil
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
1
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
t
.
Run
(
"second get"
,
func
(
t
*
testing
.
T
)
{
accessTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
accessTimestamp
})()
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
.
Data
(),
ch
.
Data
())
}
t
.
Run
(
"retrieve indexes"
,
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
uploadTimestamp
,
accessTimestamp
))
t
.
Run
(
"gc index"
,
newGCIndexTest
(
db
,
ch
,
uploadTimestamp
,
accessTimestamp
,
1
,
nil
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
1
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
t
.
Run
(
"multi"
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
db
.
GetMulti
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
if
!
bytes
.
Equal
(
got
[
0
]
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
[
0
]
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
[
0
]
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
[
0
]
.
Data
(),
ch
.
Data
())
}
t
.
Run
(
"retrieve indexes"
,
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
uploadTimestamp
,
uploadTimestamp
))
t
.
Run
(
"gc index"
,
newGCIndexTest
(
db
,
ch
,
uploadTimestamp
,
uploadTimestamp
,
1
,
nil
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
1
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
}
// TestModeGetSync validates ModeGetSync index values on the provided DB.
func
TestModeGetSync
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
uploadTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
uploadTimestamp
})()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetSync
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
.
Data
(),
ch
.
Data
())
}
t
.
Run
(
"retrieve indexes"
,
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
uploadTimestamp
,
0
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
0
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
t
.
Run
(
"multi"
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
db
.
GetMulti
(
context
.
Background
(),
chunk
.
ModeGetSync
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
got
[
0
]
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %x, want %x"
,
got
[
0
]
.
Address
(),
ch
.
Address
())
}
if
!
bytes
.
Equal
(
got
[
0
]
.
Data
(),
ch
.
Data
())
{
t
.
Errorf
(
"got chunk data %x, want %x"
,
got
[
0
]
.
Data
(),
ch
.
Data
())
}
})
}
// setTestHookUpdateGC sets testHookUpdateGC and
// returns a function that will reset it to the
// value before the change.
func
setTestHookUpdateGC
(
h
func
())
(
reset
func
())
{
current
:=
testHookUpdateGC
reset
=
func
()
{
testHookUpdateGC
=
current
}
testHookUpdateGC
=
h
return
reset
}
// TestSetTestHookUpdateGC tests if setTestHookUpdateGC changes
// testHookUpdateGC function correctly and if its reset function
// resets the original function.
func
TestSetTestHookUpdateGC
(
t
*
testing
.
T
)
{
// Set the current function after the test finishes.
defer
func
(
h
func
())
{
testHookUpdateGC
=
h
}(
testHookUpdateGC
)
// expected value for the unchanged function
original
:=
1
// expected value for the changed function
changed
:=
2
// this variable will be set with two different functions
var
got
int
// define the original (unchanged) functions
testHookUpdateGC
=
func
()
{
got
=
original
}
// set got variable
testHookUpdateGC
()
// test if got variable is set correctly
if
got
!=
original
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
original
)
}
// set the new function
reset
:=
setTestHookUpdateGC
(
func
()
{
got
=
changed
})
// set got variable
testHookUpdateGC
()
// test if got variable is set correctly to changed value
if
got
!=
changed
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
changed
)
}
// set the function to the original one
reset
()
// set got variable
testHookUpdateGC
()
// test if got variable is set correctly to original value
if
got
!=
original
{
t
.
Errorf
(
"got hook value %v, want %v"
,
got
,
original
)
}
}
pkg/storage/localstore/mode_has.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
)
// Has returns true if the chunk is stored in database.
func
(
db
*
DB
)
Has
(
ctx
context
.
Context
,
addr
chunk
.
Address
)
(
bool
,
error
)
{
metricName
:=
"localstore/Has"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
has
,
err
:=
db
.
retrievalDataIndex
.
Has
(
addressToItem
(
addr
))
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
return
has
,
err
}
// HasMulti returns a slice of booleans which represent if the provided chunks
// are stored in database.
func
(
db
*
DB
)
HasMulti
(
ctx
context
.
Context
,
addrs
...
chunk
.
Address
)
([]
bool
,
error
)
{
metricName
:=
"localstore/HasMulti"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
have
,
err
:=
db
.
retrievalDataIndex
.
HasMulti
(
addressesToItems
(
addrs
...
)
...
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
return
have
,
err
}
pkg/storage/localstore/mode_has_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"fmt"
"math/rand"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
)
// TestHas validates that Has method is returning true for
// the stored chunk and false for one that is not stored.
func
TestHas
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
has
,
err
:=
db
.
Has
(
context
.
Background
(),
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
has
{
t
.
Error
(
"chunk not found"
)
}
missingChunk
:=
generateTestRandomChunk
()
has
,
err
=
db
.
Has
(
context
.
Background
(),
missingChunk
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
has
{
t
.
Error
(
"unexpected chunk is found"
)
}
}
// TestHasMulti validates that HasMulti method is returning correct boolean
// slice for stored chunks.
func
TestHasMulti
(
t
*
testing
.
T
)
{
r
:=
rand
.
New
(
rand
.
NewSource
(
time
.
Now
()
.
UnixNano
()))
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
want
:=
make
([]
bool
,
tc
.
count
)
for
i
,
ch
:=
range
chunks
{
if
r
.
Intn
(
2
)
==
0
{
// randomly exclude half of the chunks
continue
}
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
want
[
i
]
=
true
}
got
,
err
:=
db
.
HasMulti
(
context
.
Background
(),
chunkAddresses
(
chunks
)
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
fmt
.
Sprint
(
got
)
!=
fmt
.
Sprint
(
want
)
{
t
.
Errorf
(
"got %v, want %v"
,
got
,
want
)
}
})
}
}
pkg/storage/localstore/mode_put.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"fmt"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
// Put stores Chunks to database and depending
// on the Putter mode, it updates required indexes.
// Put is required to implement chunk.Store
// interface.
func
(
db
*
DB
)
Put
(
ctx
context
.
Context
,
mode
chunk
.
ModePut
,
chs
...
chunk
.
Chunk
)
(
exist
[]
bool
,
err
error
)
{
metricName
:=
fmt
.
Sprintf
(
"localstore/Put/%s"
,
mode
)
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
exist
,
err
=
db
.
put
(
mode
,
chs
...
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
return
exist
,
err
}
// put stores Chunks to database and updates other indexes. It acquires lockAddr
// to protect two calls of this function for the same address in parallel. Item
// fields Address and Data must not be with their nil values. If chunks with the
// same address are passed in arguments, only the first chunk will be stored,
// and following ones will have exist set to true for their index in exist
// slice. This is the same behaviour as if the same chunks are passed one by one
// in multiple put method calls.
func
(
db
*
DB
)
put
(
mode
chunk
.
ModePut
,
chs
...
chunk
.
Chunk
)
(
exist
[]
bool
,
err
error
)
{
// protect parallel updates
db
.
batchMu
.
Lock
()
defer
db
.
batchMu
.
Unlock
()
batch
:=
new
(
leveldb
.
Batch
)
// variables that provide information for operations
// to be done after write batch function successfully executes
var
gcSizeChange
int64
// number to add or subtract from gcSize
var
triggerPushFeed
bool
// signal push feed subscriptions to iterate
triggerPullFeed
:=
make
(
map
[
uint8
]
struct
{})
// signal pull feed subscriptions to iterate
exist
=
make
([]
bool
,
len
(
chs
))
// A lazy populated map of bin ids to properly set
// BinID values for new chunks based on initial value from database
// and incrementing them.
// Values from this map are stored with the batch
binIDs
:=
make
(
map
[
uint8
]
uint64
)
switch
mode
{
case
chunk
.
ModePutRequest
:
for
i
,
ch
:=
range
chs
{
if
containsChunk
(
ch
.
Address
(),
chs
[
:
i
]
...
)
{
exist
[
i
]
=
true
continue
}
exists
,
c
,
err
:=
db
.
putRequest
(
batch
,
binIDs
,
chunkToItem
(
ch
))
if
err
!=
nil
{
return
nil
,
err
}
exist
[
i
]
=
exists
gcSizeChange
+=
c
}
case
chunk
.
ModePutUpload
:
for
i
,
ch
:=
range
chs
{
if
containsChunk
(
ch
.
Address
(),
chs
[
:
i
]
...
)
{
exist
[
i
]
=
true
continue
}
exists
,
c
,
err
:=
db
.
putUpload
(
batch
,
binIDs
,
chunkToItem
(
ch
))
if
err
!=
nil
{
return
nil
,
err
}
exist
[
i
]
=
exists
if
!
exists
{
// chunk is new so, trigger subscription feeds
// after the batch is successfully written
triggerPullFeed
[
db
.
po
(
ch
.
Address
())]
=
struct
{}{}
triggerPushFeed
=
true
}
gcSizeChange
+=
c
}
case
chunk
.
ModePutSync
:
for
i
,
ch
:=
range
chs
{
if
containsChunk
(
ch
.
Address
(),
chs
[
:
i
]
...
)
{
exist
[
i
]
=
true
continue
}
exists
,
c
,
err
:=
db
.
putSync
(
batch
,
binIDs
,
chunkToItem
(
ch
))
if
err
!=
nil
{
return
nil
,
err
}
exist
[
i
]
=
exists
if
!
exists
{
// chunk is new so, trigger pull subscription feed
// after the batch is successfully written
triggerPullFeed
[
db
.
po
(
ch
.
Address
())]
=
struct
{}{}
}
gcSizeChange
+=
c
}
default
:
return
nil
,
ErrInvalidMode
}
for
po
,
id
:=
range
binIDs
{
db
.
binIDs
.
PutInBatch
(
batch
,
uint64
(
po
),
id
)
}
err
=
db
.
incGCSizeInBatch
(
batch
,
gcSizeChange
)
if
err
!=
nil
{
return
nil
,
err
}
err
=
db
.
shed
.
WriteBatch
(
batch
)
if
err
!=
nil
{
return
nil
,
err
}
for
po
:=
range
triggerPullFeed
{
db
.
triggerPullSubscriptions
(
po
)
}
if
triggerPushFeed
{
db
.
triggerPushSubscriptions
()
}
return
exist
,
nil
}
// putRequest adds an Item to the batch by updating required indexes:
// - put to indexes: retrieve, gc
// - it does not enter the syncpool
// The batch can be written to the database.
// Provided batch and binID map are updated.
func
(
db
*
DB
)
putRequest
(
batch
*
leveldb
.
Batch
,
binIDs
map
[
uint8
]
uint64
,
item
shed
.
Item
)
(
exists
bool
,
gcSizeChange
int64
,
err
error
)
{
i
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
switch
err
{
case
nil
:
exists
=
true
item
.
StoreTimestamp
=
i
.
StoreTimestamp
item
.
BinID
=
i
.
BinID
case
leveldb
.
ErrNotFound
:
// no chunk accesses
exists
=
false
default
:
return
false
,
0
,
err
}
if
item
.
StoreTimestamp
==
0
{
item
.
StoreTimestamp
=
now
()
}
if
item
.
BinID
==
0
{
item
.
BinID
,
err
=
db
.
incBinID
(
binIDs
,
db
.
po
(
item
.
Address
))
if
err
!=
nil
{
return
false
,
0
,
err
}
}
gcSizeChange
,
err
=
db
.
setGC
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
err
=
db
.
retrievalDataIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
return
exists
,
gcSizeChange
,
nil
}
// putUpload adds an Item to the batch by updating required indexes:
// - put to indexes: retrieve, push, pull
// The batch can be written to the database.
// Provided batch and binID map are updated.
func
(
db
*
DB
)
putUpload
(
batch
*
leveldb
.
Batch
,
binIDs
map
[
uint8
]
uint64
,
item
shed
.
Item
)
(
exists
bool
,
gcSizeChange
int64
,
err
error
)
{
exists
,
err
=
db
.
retrievalDataIndex
.
Has
(
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
if
exists
{
if
db
.
putToGCCheck
(
item
.
Address
)
{
gcSizeChange
,
err
=
db
.
setGC
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
}
return
true
,
gcSizeChange
,
nil
}
anonymous
:=
false
if
db
.
tags
!=
nil
&&
item
.
Tag
!=
0
{
tag
,
err
:=
db
.
tags
.
Get
(
item
.
Tag
)
if
err
!=
nil
{
return
false
,
0
,
err
}
anonymous
=
tag
.
Anonymous
}
item
.
StoreTimestamp
=
now
()
item
.
BinID
,
err
=
db
.
incBinID
(
binIDs
,
db
.
po
(
item
.
Address
))
if
err
!=
nil
{
return
false
,
0
,
err
}
err
=
db
.
retrievalDataIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
err
=
db
.
pullIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
if
!
anonymous
{
err
=
db
.
pushIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
}
if
db
.
putToGCCheck
(
item
.
Address
)
{
// TODO: this might result in an edge case where a node
// that has very little storage and uploads using an anonymous
// upload will have some of the content GCd before being able
// to sync it
gcSizeChange
,
err
=
db
.
setGC
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
}
return
false
,
gcSizeChange
,
nil
}
// putSync adds an Item to the batch by updating required indexes:
// - put to indexes: retrieve, pull
// The batch can be written to the database.
// Provided batch and binID map are updated.
func
(
db
*
DB
)
putSync
(
batch
*
leveldb
.
Batch
,
binIDs
map
[
uint8
]
uint64
,
item
shed
.
Item
)
(
exists
bool
,
gcSizeChange
int64
,
err
error
)
{
exists
,
err
=
db
.
retrievalDataIndex
.
Has
(
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
if
exists
{
if
db
.
putToGCCheck
(
item
.
Address
)
{
gcSizeChange
,
err
=
db
.
setGC
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
}
return
true
,
gcSizeChange
,
nil
}
item
.
StoreTimestamp
=
now
()
item
.
BinID
,
err
=
db
.
incBinID
(
binIDs
,
db
.
po
(
item
.
Address
))
if
err
!=
nil
{
return
false
,
0
,
err
}
err
=
db
.
retrievalDataIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
err
=
db
.
pullIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
if
db
.
putToGCCheck
(
item
.
Address
)
{
// TODO: this might result in an edge case where a node
// that has very little storage and uploads using an anonymous
// upload will have some of the content GCd before being able
// to sync it
gcSizeChange
,
err
=
db
.
setGC
(
batch
,
item
)
if
err
!=
nil
{
return
false
,
0
,
err
}
}
return
false
,
gcSizeChange
,
nil
}
// setGC is a helper function used to add chunks to the retrieval access
// index and the gc index in the cases that the putToGCCheck condition
// warrants a gc set. this is to mitigate index leakage in edge cases where
// a chunk is added to a node's localstore and given that the chunk is
// already within that node's NN (thus, it can be added to the gc index
// safely)
func
(
db
*
DB
)
setGC
(
batch
*
leveldb
.
Batch
,
item
shed
.
Item
)
(
gcSizeChange
int64
,
err
error
)
{
if
item
.
BinID
==
0
{
i
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
return
0
,
err
}
item
.
BinID
=
i
.
BinID
}
i
,
err
:=
db
.
retrievalAccessIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
AccessTimestamp
=
i
.
AccessTimestamp
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
--
case
leveldb
.
ErrNotFound
:
// the chunk is not accessed before
default
:
return
0
,
err
}
item
.
AccessTimestamp
=
now
()
err
=
db
.
retrievalAccessIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
gcIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
++
return
gcSizeChange
,
nil
}
// incBinID is a helper function for db.put* methods that increments bin id
// based on the current value in the database. This function must be called under
// a db.batchMu lock. Provided binID map is updated.
func
(
db
*
DB
)
incBinID
(
binIDs
map
[
uint8
]
uint64
,
po
uint8
)
(
id
uint64
,
err
error
)
{
if
_
,
ok
:=
binIDs
[
po
];
!
ok
{
binIDs
[
po
],
err
=
db
.
binIDs
.
Get
(
uint64
(
po
))
if
err
!=
nil
{
return
0
,
err
}
}
binIDs
[
po
]
++
return
binIDs
[
po
],
nil
}
// containsChunk returns true if the chunk with a specific address
// is present in the provided chunk slice.
func
containsChunk
(
addr
chunk
.
Address
,
chs
...
chunk
.
Chunk
)
bool
{
for
_
,
c
:=
range
chs
{
if
bytes
.
Equal
(
addr
,
c
.
Address
())
{
return
true
}
}
return
false
}
pkg/storage/localstore/mode_put_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
"github.com/syndtr/goleveldb/leveldb"
)
// TestModePutRequest validates ModePutRequest index values on the provided DB.
func
TestModePutRequest
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
// keep the record when the chunk is stored
var
storeTimestamp
int64
t
.
Run
(
"first put"
,
func
(
t
*
testing
.
T
)
{
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
storeTimestamp
=
wantTimestamp
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutRequest
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
_
,
ch
:=
range
chunks
{
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
wantTimestamp
,
wantTimestamp
)(
t
)
}
newItemsCountTest
(
db
.
gcIndex
,
tc
.
count
)(
t
)
newIndexGCSizeTest
(
db
)(
t
)
})
t
.
Run
(
"second put"
,
func
(
t
*
testing
.
T
)
{
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutRequest
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
_
,
ch
:=
range
chunks
{
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
storeTimestamp
,
wantTimestamp
)(
t
)
}
newItemsCountTest
(
db
.
gcIndex
,
tc
.
count
)(
t
)
newIndexGCSizeTest
(
db
)(
t
)
})
})
}
}
// TestModePutSync validates ModePutSync index values on the provided DB.
func
TestModePutSync
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutSync
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
ch
:=
range
chunks
{
po
:=
db
.
po
(
ch
.
Address
())
binIDs
[
po
]
++
newRetrieveIndexesTest
(
db
,
ch
,
wantTimestamp
,
0
)(
t
)
newPullIndexTest
(
db
,
ch
,
binIDs
[
po
],
nil
)(
t
)
}
})
}
}
// TestModePutUpload validates ModePutUpload index values on the provided DB.
func
TestModePutUpload
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
ch
:=
range
chunks
{
po
:=
db
.
po
(
ch
.
Address
())
binIDs
[
po
]
++
newRetrieveIndexesTest
(
db
,
ch
,
wantTimestamp
,
0
)(
t
)
newPullIndexTest
(
db
,
ch
,
binIDs
[
po
],
nil
)(
t
)
newPushIndexTest
(
db
,
ch
,
wantTimestamp
,
nil
)(
t
)
}
})
}
}
// TestModePutUpload_parallel uploads chunks in parallel
// and validates if all chunks can be retrieved with correct data.
func
TestModePutUpload_parallel
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
[]
struct
{
name
string
count
int
}{
{
name
:
"one"
,
count
:
1
,
},
{
name
:
"two"
,
count
:
2
,
},
{
name
:
"eight"
,
count
:
8
,
},
}
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
uploadsCount
:=
100
workerCount
:=
100
chunksChan
:=
make
(
chan
[]
chunk
.
Chunk
)
errChan
:=
make
(
chan
error
)
doneChan
:=
make
(
chan
struct
{})
defer
close
(
doneChan
)
// start uploader workers
for
i
:=
0
;
i
<
workerCount
;
i
++
{
go
func
(
i
int
)
{
for
{
select
{
case
chunks
,
ok
:=
<-
chunksChan
:
if
!
ok
{
return
}
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
...
)
select
{
case
errChan
<-
err
:
case
<-
doneChan
:
}
case
<-
doneChan
:
return
}
}
}(
i
)
}
chunks
:=
make
([]
chunk
.
Chunk
,
0
)
var
chunksMu
sync
.
Mutex
// send chunks to workers
go
func
()
{
for
i
:=
0
;
i
<
uploadsCount
;
i
++
{
chs
:=
generateTestRandomChunks
(
tc
.
count
)
select
{
case
chunksChan
<-
chs
:
case
<-
doneChan
:
return
}
chunksMu
.
Lock
()
chunks
=
append
(
chunks
,
chs
...
)
chunksMu
.
Unlock
()
}
close
(
chunksChan
)
}()
// validate every error from workers
for
i
:=
0
;
i
<
uploadsCount
;
i
++
{
err
:=
<-
errChan
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
// get every chunk and validate its data
chunksMu
.
Lock
()
defer
chunksMu
.
Unlock
()
for
_
,
ch
:=
range
chunks
{
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
got
.
Data
(),
ch
.
Data
())
{
t
.
Fatalf
(
"got chunk %s data %x, want %x"
,
ch
.
Address
()
.
Hex
(),
got
.
Data
(),
ch
.
Data
())
}
}
})
}
}
// TestModePut_sameChunk puts the same chunk multiple times
// and validates that all relevant indexes have only one item
// in them.
func
TestModePut_sameChunk
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
for
_
,
tcn
:=
range
[]
struct
{
name
string
mode
chunk
.
ModePut
pullIndex
bool
pushIndex
bool
}{
{
name
:
"ModePutRequest"
,
mode
:
chunk
.
ModePutRequest
,
pullIndex
:
false
,
pushIndex
:
false
,
},
{
name
:
"ModePutUpload"
,
mode
:
chunk
.
ModePutUpload
,
pullIndex
:
true
,
pushIndex
:
true
,
},
{
name
:
"ModePutSync"
,
mode
:
chunk
.
ModePutSync
,
pullIndex
:
true
,
pushIndex
:
false
,
},
}
{
t
.
Run
(
tcn
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Parallel
()
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
for
i
:=
0
;
i
<
10
;
i
++
{
exist
,
err
:=
db
.
Put
(
context
.
Background
(),
tcn
.
mode
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
_
,
exists
:=
range
exist
{
switch
exists
{
case
false
:
if
i
!=
0
{
t
.
Fatal
(
"should not exist only on first Put"
)
}
case
true
:
if
i
==
0
{
t
.
Fatal
(
"should exist on all cases other than the first one"
)
}
}
}
count
:=
func
(
b
bool
)
(
c
int
)
{
if
b
{
return
tc
.
count
}
return
0
}
newItemsCountTest
(
db
.
retrievalDataIndex
,
tc
.
count
)(
t
)
newItemsCountTest
(
db
.
pullIndex
,
count
(
tcn
.
pullIndex
))(
t
)
newItemsCountTest
(
db
.
pushIndex
,
count
(
tcn
.
pushIndex
))(
t
)
}
})
}
})
}
}
// TestModePutSync_addToGc validates ModePut* with PutSetCheckFunc stub results
// in the added chunk to show up in GC index
func
TestModePut_addToGc
(
t
*
testing
.
T
)
{
retVal
:=
true
// PutSetCheckFunc's output is toggled from the test case
opts
:=
&
Options
{
PutToGCCheck
:
func
(
_
[]
byte
)
bool
{
return
retVal
}}
for
_
,
m
:=
range
[]
struct
{
mode
chunk
.
ModePut
putToGc
bool
}{
{
mode
:
chunk
.
ModePutSync
,
putToGc
:
true
},
{
mode
:
chunk
.
ModePutSync
,
putToGc
:
false
},
{
mode
:
chunk
.
ModePutUpload
,
putToGc
:
true
},
{
mode
:
chunk
.
ModePutUpload
,
putToGc
:
false
},
{
mode
:
chunk
.
ModePutRequest
,
putToGc
:
true
},
// in ModePutRequest we always insert to GC, so putToGc=false not needed
}
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
retVal
=
m
.
putToGc
db
,
cleanupFunc
:=
newTestDB
(
t
,
opts
)
defer
cleanupFunc
()
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
m
.
mode
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
ch
:=
range
chunks
{
po
:=
db
.
po
(
ch
.
Address
())
binIDs
[
po
]
++
var
wantErr
error
if
!
m
.
putToGc
{
wantErr
=
leveldb
.
ErrNotFound
}
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
wantTimestamp
,
wantTimestamp
)
newGCIndexTest
(
db
,
ch
,
wantTimestamp
,
wantTimestamp
,
binIDs
[
po
],
wantErr
)(
t
)
}
})
}
}
}
// TestModePutSync_addToGcExisting validates ModePut* with PutSetCheckFunc stub results
// in the added chunk to show up in GC index
func
TestModePut_addToGcExisting
(
t
*
testing
.
T
)
{
retVal
:=
true
// PutSetCheckFunc's output is toggled from the test case
opts
:=
&
Options
{
PutToGCCheck
:
func
(
_
[]
byte
)
bool
{
return
retVal
}}
for
_
,
m
:=
range
[]
struct
{
mode
chunk
.
ModePut
putToGc
bool
}{
{
mode
:
chunk
.
ModePutSync
,
putToGc
:
true
},
{
mode
:
chunk
.
ModePutSync
,
putToGc
:
false
},
{
mode
:
chunk
.
ModePutUpload
,
putToGc
:
true
},
{
mode
:
chunk
.
ModePutUpload
,
putToGc
:
false
},
{
mode
:
chunk
.
ModePutRequest
,
putToGc
:
true
},
// in ModePutRequest we always insert to GC, so putToGc=false not needed
}
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
retVal
=
m
.
putToGc
db
,
cleanupFunc
:=
newTestDB
(
t
,
opts
)
defer
cleanupFunc
()
wantStoreTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantStoreTimestamp
})()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
m
.
mode
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
time
.
Sleep
(
1
*
time
.
Millisecond
)
// change the timestamp, put the chunks again and
// expect the access timestamp to change
wantAccessTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantAccessTimestamp
})()
_
,
err
=
db
.
Put
(
context
.
Background
(),
m
.
mode
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
ch
:=
range
chunks
{
po
:=
db
.
po
(
ch
.
Address
())
binIDs
[
po
]
++
var
wantErr
error
if
!
m
.
putToGc
{
wantErr
=
leveldb
.
ErrNotFound
}
newRetrieveIndexesTestWithAccess
(
db
,
ch
,
wantStoreTimestamp
,
wantAccessTimestamp
)
newGCIndexTest
(
db
,
ch
,
wantStoreTimestamp
,
wantAccessTimestamp
,
binIDs
[
po
],
wantErr
)(
t
)
}
})
}
}
}
// TestPutDuplicateChunks validates the expected behaviour for
// passing duplicate chunks to the Put method.
func
TestPutDuplicateChunks
(
t
*
testing
.
T
)
{
for
_
,
mode
:=
range
[]
chunk
.
ModePut
{
chunk
.
ModePutUpload
,
chunk
.
ModePutRequest
,
chunk
.
ModePutSync
,
}
{
t
.
Run
(
mode
.
String
(),
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
ch
:=
generateTestRandomChunk
()
exist
,
err
:=
db
.
Put
(
context
.
Background
(),
mode
,
ch
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
exist
[
0
]
{
t
.
Error
(
"first chunk should not exist"
)
}
if
!
exist
[
1
]
{
t
.
Error
(
"second chunk should exist"
)
}
newItemsCountTest
(
db
.
retrievalDataIndex
,
1
)(
t
)
got
,
err
:=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetLookup
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
got
.
Address
(),
ch
.
Address
())
{
t
.
Errorf
(
"got chunk address %s, want %s"
,
got
.
Address
()
.
Hex
(),
ch
.
Address
()
.
Hex
())
}
})
}
}
// BenchmarkPutUpload runs a series of benchmarks that upload
// a specific number of chunks in parallel.
//
// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014)
//
// # go test -benchmem -run=none github.com/ethersphere/swarm/storage/localstore -bench BenchmarkPutUpload -v
//
// goos: darwin
// goarch: amd64
// pkg: github.com/ethersphere/swarm/storage/localstore
// BenchmarkPutUpload/count_100_parallel_1-8 300 5107704 ns/op 2081461 B/op 2374 allocs/op
// BenchmarkPutUpload/count_100_parallel_2-8 300 5411742 ns/op 2081608 B/op 2364 allocs/op
// BenchmarkPutUpload/count_100_parallel_4-8 500 3704964 ns/op 2081696 B/op 2324 allocs/op
// BenchmarkPutUpload/count_100_parallel_8-8 500 2932663 ns/op 2082594 B/op 2295 allocs/op
// BenchmarkPutUpload/count_100_parallel_16-8 500 3117157 ns/op 2085438 B/op 2282 allocs/op
// BenchmarkPutUpload/count_100_parallel_32-8 500 3449122 ns/op 2089721 B/op 2286 allocs/op
// BenchmarkPutUpload/count_1000_parallel_1-8 20 79784470 ns/op 25211240 B/op 23225 allocs/op
// BenchmarkPutUpload/count_1000_parallel_2-8 20 75422164 ns/op 25210730 B/op 23187 allocs/op
// BenchmarkPutUpload/count_1000_parallel_4-8 20 70698378 ns/op 25206522 B/op 22692 allocs/op
// BenchmarkPutUpload/count_1000_parallel_8-8 20 71285528 ns/op 25213436 B/op 22345 allocs/op
// BenchmarkPutUpload/count_1000_parallel_16-8 20 71301826 ns/op 25205040 B/op 22090 allocs/op
// BenchmarkPutUpload/count_1000_parallel_32-8 30 57713506 ns/op 25219781 B/op 21848 allocs/op
// BenchmarkPutUpload/count_10000_parallel_1-8 2 656719345 ns/op 216792908 B/op 248940 allocs/op
// BenchmarkPutUpload/count_10000_parallel_2-8 2 646301962 ns/op 216730800 B/op 248270 allocs/op
// BenchmarkPutUpload/count_10000_parallel_4-8 2 532784228 ns/op 216667080 B/op 241910 allocs/op
// BenchmarkPutUpload/count_10000_parallel_8-8 3 494290188 ns/op 216297749 B/op 236247 allocs/op
// BenchmarkPutUpload/count_10000_parallel_16-8 3 483485315 ns/op 216060384 B/op 231090 allocs/op
// BenchmarkPutUpload/count_10000_parallel_32-8 3 434461294 ns/op 215371280 B/op 224800 allocs/op
// BenchmarkPutUpload/count_100000_parallel_1-8 1 22767894338 ns/op 2331372088 B/op 4049876 allocs/op
// BenchmarkPutUpload/count_100000_parallel_2-8 1 25347872677 ns/op 2344140160 B/op 4106763 allocs/op
// BenchmarkPutUpload/count_100000_parallel_4-8 1 23580460174 ns/op 2338582576 B/op 4027452 allocs/op
// BenchmarkPutUpload/count_100000_parallel_8-8 1 22197559193 ns/op 2321803496 B/op 3877553 allocs/op
// BenchmarkPutUpload/count_100000_parallel_16-8 1 22527046476 ns/op 2327854800 B/op 3885455 allocs/op
// BenchmarkPutUpload/count_100000_parallel_32-8 1 21332243613 ns/op 2299654568 B/op 3697181 allocs/op
// PASS
func
BenchmarkPutUpload
(
b
*
testing
.
B
)
{
for
_
,
count
:=
range
[]
int
{
100
,
1000
,
10000
,
100000
,
}
{
for
_
,
maxParallelUploads
:=
range
[]
int
{
1
,
2
,
4
,
8
,
16
,
32
,
}
{
name
:=
fmt
.
Sprintf
(
"count %v parallel %v"
,
count
,
maxParallelUploads
)
b
.
Run
(
name
,
func
(
b
*
testing
.
B
)
{
for
n
:=
0
;
n
<
b
.
N
;
n
++
{
benchmarkPutUpload
(
b
,
nil
,
count
,
maxParallelUploads
)
}
})
}
}
}
// benchmarkPutUpload runs a benchmark by uploading a specific number
// of chunks with specified max parallel uploads.
func
benchmarkPutUpload
(
b
*
testing
.
B
,
o
*
Options
,
count
,
maxParallelUploads
int
)
{
b
.
StopTimer
()
db
,
cleanupFunc
:=
newTestDB
(
b
,
o
)
defer
cleanupFunc
()
chunks
:=
make
([]
chunk
.
Chunk
,
count
)
for
i
:=
0
;
i
<
count
;
i
++
{
chunks
[
i
]
=
generateTestRandomChunk
()
}
errs
:=
make
(
chan
error
)
b
.
StartTimer
()
go
func
()
{
sem
:=
make
(
chan
struct
{},
maxParallelUploads
)
for
i
:=
0
;
i
<
count
;
i
++
{
sem
<-
struct
{}{}
go
func
(
i
int
)
{
defer
func
()
{
<-
sem
}()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
[
i
])
errs
<-
err
}(
i
)
}
}()
for
i
:=
0
;
i
<
count
;
i
++
{
err
:=
<-
errs
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
}
}
pkg/storage/localstore/mode_set.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"errors"
"fmt"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/log"
"github.com/syndtr/goleveldb/leveldb"
)
// Set updates database indexes for
// chunks represented by provided addresses.
// Set is required to implement chunk.Store
// interface.
func
(
db
*
DB
)
Set
(
ctx
context
.
Context
,
mode
chunk
.
ModeSet
,
addrs
...
chunk
.
Address
)
(
err
error
)
{
metricName
:=
fmt
.
Sprintf
(
"localstore/Set/%s"
,
mode
)
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
defer
totalTimeMetric
(
metricName
,
time
.
Now
())
err
=
db
.
set
(
mode
,
addrs
...
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/error"
,
nil
)
.
Inc
(
1
)
}
return
err
}
// set updates database indexes for
// chunks represented by provided addresses.
// It acquires lockAddr to protect two calls
// of this function for the same address in parallel.
func
(
db
*
DB
)
set
(
mode
chunk
.
ModeSet
,
addrs
...
chunk
.
Address
)
(
err
error
)
{
// protect parallel updates
db
.
batchMu
.
Lock
()
defer
db
.
batchMu
.
Unlock
()
batch
:=
new
(
leveldb
.
Batch
)
// variables that provide information for operations
// to be done after write batch function successfully executes
var
gcSizeChange
int64
// number to add or subtract from gcSize
triggerPullFeed
:=
make
(
map
[
uint8
]
struct
{})
// signal pull feed subscriptions to iterate
switch
mode
{
case
chunk
.
ModeSetAccess
:
// A lazy populated map of bin ids to properly set
// BinID values for new chunks based on initial value from database
// and incrementing them.
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
addr
:=
range
addrs
{
po
:=
db
.
po
(
addr
)
c
,
err
:=
db
.
setAccess
(
batch
,
binIDs
,
addr
,
po
)
if
err
!=
nil
{
return
err
}
gcSizeChange
+=
c
triggerPullFeed
[
po
]
=
struct
{}{}
}
for
po
,
id
:=
range
binIDs
{
db
.
binIDs
.
PutInBatch
(
batch
,
uint64
(
po
),
id
)
}
case
chunk
.
ModeSetSyncPush
,
chunk
.
ModeSetSyncPull
:
for
_
,
addr
:=
range
addrs
{
c
,
err
:=
db
.
setSync
(
batch
,
addr
,
mode
)
if
err
!=
nil
{
return
err
}
gcSizeChange
+=
c
}
case
chunk
.
ModeSetRemove
:
for
_
,
addr
:=
range
addrs
{
c
,
err
:=
db
.
setRemove
(
batch
,
addr
)
if
err
!=
nil
{
return
err
}
gcSizeChange
+=
c
}
case
chunk
.
ModeSetPin
:
for
_
,
addr
:=
range
addrs
{
err
:=
db
.
setPin
(
batch
,
addr
)
if
err
!=
nil
{
return
err
}
}
case
chunk
.
ModeSetUnpin
:
for
_
,
addr
:=
range
addrs
{
err
:=
db
.
setUnpin
(
batch
,
addr
)
if
err
!=
nil
{
return
err
}
}
default
:
return
ErrInvalidMode
}
err
=
db
.
incGCSizeInBatch
(
batch
,
gcSizeChange
)
if
err
!=
nil
{
return
err
}
err
=
db
.
shed
.
WriteBatch
(
batch
)
if
err
!=
nil
{
return
err
}
for
po
:=
range
triggerPullFeed
{
db
.
triggerPullSubscriptions
(
po
)
}
return
nil
}
// setAccess sets the chunk access time by updating required indexes:
// - add to pull, insert to gc
// Provided batch and binID map are updated.
func
(
db
*
DB
)
setAccess
(
batch
*
leveldb
.
Batch
,
binIDs
map
[
uint8
]
uint64
,
addr
chunk
.
Address
,
po
uint8
)
(
gcSizeChange
int64
,
err
error
)
{
item
:=
addressToItem
(
addr
)
// need to get access timestamp here as it is not
// provided by the access function, and it is not
// a property of a chunk provided to Accessor.Put.
i
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
StoreTimestamp
=
i
.
StoreTimestamp
item
.
BinID
=
i
.
BinID
case
leveldb
.
ErrNotFound
:
err
=
db
.
pushIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
item
.
StoreTimestamp
=
now
()
item
.
BinID
,
err
=
db
.
incBinID
(
binIDs
,
po
)
if
err
!=
nil
{
return
0
,
err
}
default
:
return
0
,
err
}
i
,
err
=
db
.
retrievalAccessIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
AccessTimestamp
=
i
.
AccessTimestamp
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
--
case
leveldb
.
ErrNotFound
:
// the chunk is not accessed before
default
:
return
0
,
err
}
item
.
AccessTimestamp
=
now
()
err
=
db
.
retrievalAccessIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
pullIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
gcIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
++
return
gcSizeChange
,
nil
}
// setSync adds the chunk to the garbage collection after syncing by updating indexes
// - ModeSetSyncPull - the corresponding tag is incremented, pull index item tag value
// is then set to 0 to prevent duplicate increments for the same chunk synced multiple times
// - ModeSetSyncPush - the corresponding tag is incremented, then item is removed
// from push sync index
// - update to gc index happens given item does not exist in pin index
// Provided batch is updated.
func
(
db
*
DB
)
setSync
(
batch
*
leveldb
.
Batch
,
addr
chunk
.
Address
,
mode
chunk
.
ModeSet
)
(
gcSizeChange
int64
,
err
error
)
{
item
:=
addressToItem
(
addr
)
// need to get access timestamp here as it is not
// provided by the access function, and it is not
// a property of a chunk provided to Accessor.Put.
i
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
// chunk is not found,
// no need to update gc index
// just delete from the push index
// if it is there
err
=
db
.
pushIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
return
0
,
nil
}
return
0
,
err
}
item
.
StoreTimestamp
=
i
.
StoreTimestamp
item
.
BinID
=
i
.
BinID
switch
mode
{
case
chunk
.
ModeSetSyncPull
:
// if we are setting a chunk for pullsync we expect it to be in the index
// if it has a tag - we increment it and set the index item to _not_ contain the tag reference
// this prevents duplicate increments
i
,
err
:=
db
.
pullIndex
.
Get
(
item
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
// we handle this error internally, since this is an internal inconsistency of the indices
// if we return the error here - it means that for example, in stream protocol peers which we sync
// to would be dropped. this is possible when the chunk is put with ModePutRequest and ModeSetSyncPull is
// called on the same chunk (which should not happen)
log
.
Error
(
"chunk not found in pull index"
,
"addr"
,
addr
)
break
}
return
0
,
err
}
if
db
.
tags
!=
nil
&&
i
.
Tag
!=
0
{
t
,
err
:=
db
.
tags
.
Get
(
i
.
Tag
)
// increment if and only if tag is anonymous
if
err
==
nil
&&
t
.
Anonymous
{
// since pull sync does not guarantee that
// a chunk has reached its NN, we can only mark
// it as Sent
t
.
Inc
(
chunk
.
StateSent
)
// setting the tag to zero makes sure that
// we don't increment the same tag twice when syncing
// the same chunk to different peers
item
.
Tag
=
0
err
=
db
.
pullIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
}
}
case
chunk
.
ModeSetSyncPush
:
i
,
err
:=
db
.
pushIndex
.
Get
(
item
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
// we handle this error internally, since this is an internal inconsistency of the indices
// this error can happen if the chunk is put with ModePutRequest or ModePutSync
// but this function is called with ModeSetSyncPush
log
.
Error
(
"chunk not found in push index"
,
"addr"
,
addr
)
break
}
return
0
,
err
}
if
db
.
tags
!=
nil
&&
i
.
Tag
!=
0
{
t
,
err
:=
db
.
tags
.
Get
(
i
.
Tag
)
if
err
!=
nil
{
// we cannot break or return here since the function needs to
// run to end from db.pushIndex.DeleteInBatch
log
.
Error
(
"error getting tags on push sync set"
,
"uid"
,
i
.
Tag
)
}
else
{
// setting a chunk for push sync assumes the tag is not anonymous
if
t
.
Anonymous
{
return
0
,
errors
.
New
(
"got an anonymous chunk in push sync index"
)
}
t
.
Inc
(
chunk
.
StateSynced
)
}
}
err
=
db
.
pushIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
}
i
,
err
=
db
.
retrievalAccessIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
AccessTimestamp
=
i
.
AccessTimestamp
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
--
case
leveldb
.
ErrNotFound
:
// the chunk is not accessed before
default
:
return
0
,
err
}
item
.
AccessTimestamp
=
now
()
err
=
db
.
retrievalAccessIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
// Add in gcIndex only if this chunk is not pinned
ok
,
err
:=
db
.
pinIndex
.
Has
(
item
)
if
err
!=
nil
{
return
0
,
err
}
if
!
ok
{
err
=
db
.
gcIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
gcSizeChange
++
}
return
gcSizeChange
,
nil
}
// setRemove removes the chunk by updating indexes:
// - delete from retrieve, pull, gc
// Provided batch is updated.
func
(
db
*
DB
)
setRemove
(
batch
*
leveldb
.
Batch
,
addr
chunk
.
Address
)
(
gcSizeChange
int64
,
err
error
)
{
item
:=
addressToItem
(
addr
)
// need to get access timestamp here as it is not
// provided by the access function, and it is not
// a property of a chunk provided to Accessor.Put.
i
,
err
:=
db
.
retrievalAccessIndex
.
Get
(
item
)
switch
err
{
case
nil
:
item
.
AccessTimestamp
=
i
.
AccessTimestamp
case
leveldb
.
ErrNotFound
:
default
:
return
0
,
err
}
i
,
err
=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
return
0
,
err
}
item
.
StoreTimestamp
=
i
.
StoreTimestamp
item
.
BinID
=
i
.
BinID
err
=
db
.
retrievalDataIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
retrievalAccessIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
pullIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
err
=
db
.
gcIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
0
,
err
}
// a check is needed for decrementing gcSize
// as delete is not reporting if the key/value pair
// is deleted or not
if
_
,
err
:=
db
.
gcIndex
.
Get
(
item
);
err
==
nil
{
gcSizeChange
=
-
1
}
return
gcSizeChange
,
nil
}
// setPin increments pin counter for the chunk by updating
// pin index and sets the chunk to be excluded from garbage collection.
// Provided batch is updated.
func
(
db
*
DB
)
setPin
(
batch
*
leveldb
.
Batch
,
addr
chunk
.
Address
)
(
err
error
)
{
item
:=
addressToItem
(
addr
)
// Get the existing pin counter of the chunk
existingPinCounter
:=
uint64
(
0
)
pinnedChunk
,
err
:=
db
.
pinIndex
.
Get
(
item
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
// If this Address is not present in DB, then its a new entry
existingPinCounter
=
0
// Add in gcExcludeIndex of the chunk is not pinned already
err
=
db
.
gcExcludeIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
}
else
{
return
err
}
}
else
{
existingPinCounter
=
pinnedChunk
.
PinCounter
}
// Otherwise increase the existing counter by 1
item
.
PinCounter
=
existingPinCounter
+
1
err
=
db
.
pinIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
return
nil
}
// setUnpin decrements pin counter for the chunk by updating pin index.
// Provided batch is updated.
func
(
db
*
DB
)
setUnpin
(
batch
*
leveldb
.
Batch
,
addr
chunk
.
Address
)
(
err
error
)
{
item
:=
addressToItem
(
addr
)
// Get the existing pin counter of the chunk
pinnedChunk
,
err
:=
db
.
pinIndex
.
Get
(
item
)
if
err
!=
nil
{
return
err
}
// Decrement the pin counter or
// delete it from pin index if the pin counter has reached 0
if
pinnedChunk
.
PinCounter
>
1
{
item
.
PinCounter
=
pinnedChunk
.
PinCounter
-
1
err
=
db
.
pinIndex
.
PutInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
}
else
{
err
=
db
.
pinIndex
.
DeleteInBatch
(
batch
,
item
)
if
err
!=
nil
{
return
err
}
}
return
nil
}
pkg/storage/localstore/mode_set_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
tagtesting
"github.com/ethersphere/swarm/chunk/testing"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
// TestModeSetAccess validates ModeSetAccess index values on the provided DB.
func
TestModeSetAccess
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
wantTimestamp
:=
time
.
Now
()
.
UTC
()
.
UnixNano
()
defer
setNow
(
func
()
(
t
int64
)
{
return
wantTimestamp
})()
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetAccess
,
chunkAddresses
(
chunks
)
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
binIDs
:=
make
(
map
[
uint8
]
uint64
)
for
_
,
ch
:=
range
chunks
{
po
:=
db
.
po
(
ch
.
Address
())
binIDs
[
po
]
++
newPullIndexTest
(
db
,
ch
,
binIDs
[
po
],
nil
)(
t
)
newGCIndexTest
(
db
,
ch
,
wantTimestamp
,
wantTimestamp
,
binIDs
[
po
],
nil
)(
t
)
}
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
tc
.
count
))
t
.
Run
(
"pull index count"
,
newItemsCountTest
(
db
.
pullIndex
,
tc
.
count
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
}
}
// here we try to set a normal tag (that should be handled by pushsync)
// as a result we should expect the tag value to remain in the pull index
// and we expect that the tag should not be incremented by pull sync set
func
TestModeSetSyncPullNormalTag
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Tags
:
chunk
.
NewTags
()})
defer
cleanupFunc
()
tag
,
err
:=
db
.
tags
.
Create
(
"test"
,
1
,
false
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ch
:=
generateTestRandomChunk
()
.
WithTagID
(
tag
.
Uid
)
_
,
err
=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
tag
.
Inc
(
chunk
.
StateStored
)
// so we don't get an error on tag.Status later on
item
,
err
:=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
item
,
err
=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect the same tag Uid because when we set pull sync on a normal tag
// the tag Uid should remain untouched in pull index
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
// 1 stored (because incremented manually in test), 1 sent, 1 total
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
1
,
0
,
1
)
}
// TestModeSetSyncPullAnonymousTag checks that pull sync correcly increments
// counters on an anonymous tag which is expected to be handled only by pull sync
func
TestModeSetSyncPullAnonymousTag
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Tags
:
chunk
.
NewTags
()})
defer
cleanupFunc
()
tag
,
err
:=
db
.
tags
.
Create
(
"test"
,
1
,
true
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ch
:=
generateTestRandomChunk
()
.
WithTagID
(
tag
.
Uid
)
_
,
err
=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
tag
.
Inc
(
chunk
.
StateStored
)
// so we don't get an error on tag.Status later on
item
,
err
:=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
item
,
err
=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
0
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
0
)
}
// 1 stored (because incremented manually in test), 1 sent, 1 total
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
1
,
0
,
1
)
}
// TestModeSetSyncPullPushAnonymousTag creates an anonymous tag and a corresponding chunk
// then tries to Set both with push and pull Sync modes, but asserts that only the pull sync
// increments were done to the tag
func
TestModeSetSyncPullPushAnonymousTag
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Tags
:
chunk
.
NewTags
()})
defer
cleanupFunc
()
tag
,
err
:=
db
.
tags
.
Create
(
"test"
,
1
,
true
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ch
:=
generateTestRandomChunk
()
.
WithTagID
(
tag
.
Uid
)
_
,
err
=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
tag
.
Inc
(
chunk
.
StateStored
)
// so we don't get an error on tag.Status later on
item
,
err
:=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect no error here. if the item cannot be found in pushsync the rest of the
// setSync logic should be executed
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPush
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// check that the tag has been incremented
item
,
err
=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
0
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
0
)
}
// 1 stored (because incremented manually in test), 1 sent, 1 total
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
1
,
0
,
1
)
// verify that the item does not exist in the push index
item
,
err
=
db
.
pushIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
==
nil
{
t
.
Fatal
(
"expected error but got none"
)
}
}
// TestModeSetSyncPushNormalTag makes sure that push sync increments tags
// correctly on a normal tag (that is, a tag that is expected to show progress bars
// according to push sync progress)
func
TestModeSetSyncPushNormalTag
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
&
Options
{
Tags
:
chunk
.
NewTags
()})
defer
cleanupFunc
()
tag
,
err
:=
db
.
tags
.
Create
(
"test"
,
1
,
false
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ch
:=
generateTestRandomChunk
()
.
WithTagID
(
tag
.
Uid
)
_
,
err
=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
tag
.
Inc
(
chunk
.
StateStored
)
// so we don't get an error on tag.Status later on
item
,
err
:=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
0
,
0
,
1
)
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPush
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
item
,
err
=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
0
,
1
,
1
)
// call pull sync set, expect no changes
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
ch
.
Address
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
item
,
err
=
db
.
pullIndex
.
Get
(
shed
.
Item
{
Address
:
ch
.
Address
(),
BinID
:
1
,
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
tagtesting
.
CheckTag
(
t
,
tag
,
0
,
1
,
0
,
0
,
1
,
1
)
if
item
.
Tag
!=
tag
.
Uid
{
t
.
Fatalf
(
"unexpected tag id value got %d want %d"
,
item
.
Tag
,
tag
.
Uid
)
}
}
// TestModeSetRemove validates ModeSetRemove index values on the provided DB.
func
TestModeSetRemove
(
t
*
testing
.
T
)
{
for
_
,
tc
:=
range
multiChunkTestCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
generateTestRandomChunks
(
tc
.
count
)
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetRemove
,
chunkAddresses
(
chunks
)
...
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
t
.
Run
(
"retrieve indexes"
,
func
(
t
*
testing
.
T
)
{
for
_
,
ch
:=
range
chunks
{
wantErr
:=
leveldb
.
ErrNotFound
_
,
err
:=
db
.
retrievalDataIndex
.
Get
(
addressToItem
(
ch
.
Address
()))
if
err
!=
wantErr
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantErr
)
}
// access index should not be set
_
,
err
=
db
.
retrievalAccessIndex
.
Get
(
addressToItem
(
ch
.
Address
()))
if
err
!=
wantErr
{
t
.
Errorf
(
"got error %v, want %v"
,
err
,
wantErr
)
}
}
t
.
Run
(
"retrieve data index count"
,
newItemsCountTest
(
db
.
retrievalDataIndex
,
0
))
t
.
Run
(
"retrieve access index count"
,
newItemsCountTest
(
db
.
retrievalAccessIndex
,
0
))
})
for
_
,
ch
:=
range
chunks
{
newPullIndexTest
(
db
,
ch
,
0
,
leveldb
.
ErrNotFound
)(
t
)
}
t
.
Run
(
"pull index count"
,
newItemsCountTest
(
db
.
pullIndex
,
0
))
t
.
Run
(
"gc index count"
,
newItemsCountTest
(
db
.
gcIndex
,
0
))
t
.
Run
(
"gc size"
,
newIndexGCSizeTest
(
db
))
})
}
}
pkg/storage/localstore/retrieval_index_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"strconv"
"testing"
"github.com/ethersphere/swarm/chunk"
)
// BenchmarkRetrievalIndexes uploads a number of chunks in order to measure
// total time of updating their retrieval indexes by setting them
// to synced state and requesting them.
//
// This benchmark takes significant amount of time.
//
// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) show
// that two separated indexes perform better.
//
// # go test -benchmem -run=none github.com/ethersphere/swarm/storage/localstore -bench BenchmarkRetrievalIndexes -v
// goos: darwin
// goarch: amd64
// pkg: github.com/ethersphere/swarm/storage/localstore
// BenchmarkRetrievalIndexes/1000-8 20 75556686 ns/op 19033493 B/op 84500 allocs/op
// BenchmarkRetrievalIndexes/10000-8 1 1079084922 ns/op 382792064 B/op 1429644 allocs/op
// BenchmarkRetrievalIndexes/100000-8 1 16891305737 ns/op 2629165304 B/op 12465019 allocs/op
// PASS
func
BenchmarkRetrievalIndexes
(
b
*
testing
.
B
)
{
for
_
,
count
:=
range
[]
int
{
1000
,
10000
,
100000
,
}
{
b
.
Run
(
strconv
.
Itoa
(
count
)
+
"-split"
,
func
(
b
*
testing
.
B
)
{
for
n
:=
0
;
n
<
b
.
N
;
n
++
{
benchmarkRetrievalIndexes
(
b
,
nil
,
count
)
}
})
}
}
// benchmarkRetrievalIndexes is used in BenchmarkRetrievalIndexes
// to do benchmarks with a specific number of chunks and different
// database options.
func
benchmarkRetrievalIndexes
(
b
*
testing
.
B
,
o
*
Options
,
count
int
)
{
b
.
StopTimer
()
db
,
cleanupFunc
:=
newTestDB
(
b
,
o
)
defer
cleanupFunc
()
addrs
:=
make
([]
chunk
.
Address
,
count
)
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
addrs
[
i
]
=
ch
.
Address
()
}
// set update gc test hook to signal when
// update gc goroutine is done by sending to
// testHookUpdateGCChan channel, which is
// used to wait for gc index updates to be
// included in the benchmark time
testHookUpdateGCChan
:=
make
(
chan
struct
{})
defer
setTestHookUpdateGC
(
func
()
{
testHookUpdateGCChan
<-
struct
{}{}
})()
b
.
StartTimer
()
for
i
:=
0
;
i
<
count
;
i
++
{
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetSyncPull
,
addrs
[
i
])
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
_
,
err
=
db
.
Get
(
context
.
Background
(),
chunk
.
ModeGetRequest
,
addrs
[
i
])
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
// wait for update gc goroutine to be done
<-
testHookUpdateGCChan
}
}
// BenchmarkUpload compares uploading speed for different
// retrieval indexes and various number of chunks.
//
// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014).
//
// go test -benchmem -run=none github.com/ethersphere/swarm/storage/localstore -bench BenchmarkUpload -v
// goos: darwin
// goarch: amd64
// pkg: github.com/ethersphere/swarm/storage/localstore
// BenchmarkUpload/1000-8 20 59437463 ns/op 25205193 B/op 23208 allocs/op
// BenchmarkUpload/10000-8 2 580646362 ns/op 216532932 B/op 248090 allocs/op
// BenchmarkUpload/100000-8 1 22373390892 ns/op 2323055312 B/op 3995903 allocs/op
// PASS
func
BenchmarkUpload
(
b
*
testing
.
B
)
{
for
_
,
count
:=
range
[]
int
{
1000
,
10000
,
100000
,
}
{
b
.
Run
(
strconv
.
Itoa
(
count
),
func
(
b
*
testing
.
B
)
{
for
n
:=
0
;
n
<
b
.
N
;
n
++
{
benchmarkUpload
(
b
,
nil
,
count
)
}
})
}
}
// benchmarkUpload is used in BenchmarkUpload
// to do benchmarks with a specific number of chunks and different
// database options.
func
benchmarkUpload
(
b
*
testing
.
B
,
o
*
Options
,
count
int
)
{
b
.
StopTimer
()
db
,
cleanupFunc
:=
newTestDB
(
b
,
o
)
defer
cleanupFunc
()
chunks
:=
make
([]
chunk
.
Chunk
,
count
)
for
i
:=
0
;
i
<
count
;
i
++
{
chunk
:=
generateTestRandomChunk
()
chunks
[
i
]
=
chunk
}
b
.
StartTimer
()
for
i
:=
0
;
i
<
count
;
i
++
{
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
chunks
[
i
])
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
}
}
pkg/storage/localstore/schema.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The Swarm Authors
// This file is part of the Swarm library.
//
// The Swarm library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Swarm library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Swarm library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"github.com/ethersphere/swarm/log"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/opt"
)
// The DB schema we want to use. The actual/current DB schema might differ
// until migrations are run.
var
DbSchemaCurrent
=
DbSchemaDiwali
// There was a time when we had no schema at all.
const
DbSchemaNone
=
""
// "purity" is the first formal schema of LevelDB we release together with Swarm 0.3.5
const
DbSchemaPurity
=
"purity"
// "halloween" is here because we had a screw in the garbage collector index.
// Because of that we had to rebuild the GC index to get rid of erroneous
// entries and that takes a long time. This schema is used for bookkeeping,
// so rebuild index will run just once.
const
DbSchemaHalloween
=
"halloween"
const
DbSchemaSanctuary
=
"sanctuary"
// the "diwali" migration simply renames the pullIndex in localstore
const
DbSchemaDiwali
=
"diwali"
// returns true if legacy database is in the datadir
func
IsLegacyDatabase
(
datadir
string
)
bool
{
var
(
legacyDbSchemaKey
=
[]
byte
{
8
}
)
db
,
err
:=
leveldb
.
OpenFile
(
datadir
,
&
opt
.
Options
{
OpenFilesCacheCapacity
:
128
})
if
err
!=
nil
{
log
.
Error
(
"got an error while trying to open leveldb path"
,
"path"
,
datadir
,
"err"
,
err
)
return
false
}
defer
db
.
Close
()
data
,
err
:=
db
.
Get
(
legacyDbSchemaKey
,
nil
)
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
// if we haven't found anything under the legacy db schema key- we are not on legacy
return
false
}
log
.
Error
(
"got an unexpected error fetching legacy name from the database"
,
"err"
,
err
)
}
log
.
Trace
(
"checking if database scheme is legacy"
,
"schema name"
,
string
(
data
))
return
string
(
data
)
==
DbSchemaHalloween
||
string
(
data
)
==
DbSchemaPurity
}
pkg/storage/localstore/subscription_pull.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"errors"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
"github.com/syndtr/goleveldb/leveldb"
)
// SubscribePull returns a channel that provides chunk addresses and stored times from pull syncing index.
// Pull syncing index can be only subscribed to a particular proximity order bin. If since
// is not 0, the iteration will start from the since item (the item with binID == since). If until is not 0,
// only chunks stored up to this id will be sent to the channel, and the returned channel will be
// closed. The since-until interval is closed on since side, and closed on until side: [since,until]. Returned stop
// function will terminate current and further iterations without errors, and also close the returned channel.
// Make sure that you check the second returned parameter from the channel to stop iteration when its value
// is false.
func
(
db
*
DB
)
SubscribePull
(
ctx
context
.
Context
,
bin
uint8
,
since
,
until
uint64
)
(
c
<-
chan
chunk
.
Descriptor
,
stop
func
())
{
metricName
:=
"localstore/SubscribePull"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
chunkDescriptors
:=
make
(
chan
chunk
.
Descriptor
)
trigger
:=
make
(
chan
struct
{},
1
)
db
.
pullTriggersMu
.
Lock
()
if
_
,
ok
:=
db
.
pullTriggers
[
bin
];
!
ok
{
db
.
pullTriggers
[
bin
]
=
make
([]
chan
struct
{},
0
)
}
db
.
pullTriggers
[
bin
]
=
append
(
db
.
pullTriggers
[
bin
],
trigger
)
db
.
pullTriggersMu
.
Unlock
()
// send signal for the initial iteration
trigger
<-
struct
{}{}
stopChan
:=
make
(
chan
struct
{})
var
stopChanOnce
sync
.
Once
// used to provide information from the iterator to
// stop subscription when until chunk descriptor is reached
var
errStopSubscription
=
errors
.
New
(
"stop subscription"
)
db
.
subscritionsWG
.
Add
(
1
)
go
func
()
{
defer
db
.
subscritionsWG
.
Done
()
defer
metrics
.
GetOrRegisterCounter
(
metricName
+
"/stop"
,
nil
)
.
Inc
(
1
)
// close the returned chunk.Descriptor channel at the end to
// signal that the subscription is done
defer
close
(
chunkDescriptors
)
// sinceItem is the Item from which the next iteration
// should start. The first iteration starts from the first Item.
var
sinceItem
*
shed
.
Item
if
since
>
0
{
sinceItem
=
&
shed
.
Item
{
Address
:
db
.
addressInBin
(
bin
),
BinID
:
since
,
}
}
first
:=
true
// first iteration flag for SkipStartFromItem
for
{
select
{
case
<-
trigger
:
// iterate until:
// - last index Item is reached
// - subscription stop is called
// - context is done
metrics
.
GetOrRegisterCounter
(
metricName
+
"/iter"
,
nil
)
.
Inc
(
1
)
iterStart
:=
time
.
Now
()
var
count
int
err
:=
db
.
pullIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
// until chunk descriptor is sent
// break the iteration
if
until
>
0
&&
item
.
BinID
>
until
{
return
true
,
errStopSubscription
}
select
{
case
chunkDescriptors
<-
chunk
.
Descriptor
{
Address
:
item
.
Address
,
BinID
:
item
.
BinID
,
}
:
if
until
>
0
&&
item
.
BinID
==
until
{
return
true
,
errStopSubscription
}
count
++
// set next iteration start item
// when its chunk is successfully sent to channel
sinceItem
=
&
item
return
false
,
nil
case
<-
stopChan
:
// gracefully stop the iteration
// on stop
return
true
,
nil
case
<-
db
.
close
:
// gracefully stop the iteration
// on database close
return
true
,
nil
case
<-
ctx
.
Done
()
:
return
true
,
ctx
.
Err
()
}
},
&
shed
.
IterateOptions
{
StartFrom
:
sinceItem
,
// sinceItem was sent as the last Address in the previous
// iterator call, skip it in this one, but not the item with
// the provided since bin id as it should be sent to a channel
SkipStartFromItem
:
!
first
,
Prefix
:
[]
byte
{
bin
},
})
totalTimeMetric
(
metricName
+
"/iter"
,
iterStart
)
if
err
!=
nil
{
if
err
==
errStopSubscription
{
// stop subscription without any errors
// if until is reached
return
}
metrics
.
GetOrRegisterCounter
(
metricName
+
"/iter/error"
,
nil
)
.
Inc
(
1
)
log
.
Error
(
"localstore pull subscription iteration"
,
"bin"
,
bin
,
"since"
,
since
,
"until"
,
until
,
"err"
,
err
)
return
}
if
count
>
0
{
first
=
false
}
case
<-
stopChan
:
// terminate the subscription
// on stop
return
case
<-
db
.
close
:
// terminate the subscription
// on database close
return
case
<-
ctx
.
Done
()
:
err
:=
ctx
.
Err
()
if
err
!=
nil
{
log
.
Error
(
"localstore pull subscription"
,
"bin"
,
bin
,
"since"
,
since
,
"until"
,
until
,
"err"
,
err
)
}
return
}
}
}()
stop
=
func
()
{
stopChanOnce
.
Do
(
func
()
{
close
(
stopChan
)
})
db
.
pullTriggersMu
.
Lock
()
defer
db
.
pullTriggersMu
.
Unlock
()
for
i
,
t
:=
range
db
.
pullTriggers
[
bin
]
{
if
t
==
trigger
{
db
.
pullTriggers
[
bin
]
=
append
(
db
.
pullTriggers
[
bin
][
:
i
],
db
.
pullTriggers
[
bin
][
i
+
1
:
]
...
)
break
}
}
}
return
chunkDescriptors
,
stop
}
// LastPullSubscriptionBinID returns chunk bin id of the latest Chunk
// in pull syncing index for a provided bin. If there are no chunks in
// that bin, 0 value is returned.
func
(
db
*
DB
)
LastPullSubscriptionBinID
(
bin
uint8
)
(
id
uint64
,
err
error
)
{
metrics
.
GetOrRegisterCounter
(
"localstore/LastPullSubscriptionBinID"
,
nil
)
.
Inc
(
1
)
item
,
err
:=
db
.
pullIndex
.
Last
([]
byte
{
bin
})
if
err
!=
nil
{
if
err
==
leveldb
.
ErrNotFound
{
return
0
,
nil
}
return
0
,
err
}
return
item
.
BinID
,
nil
}
// triggerPullSubscriptions is used internally for starting iterations
// on Pull subscriptions for a particular bin. When new item with address
// that is in particular bin for DB's baseKey is added to pull index
// this function should be called.
func
(
db
*
DB
)
triggerPullSubscriptions
(
bin
uint8
)
{
db
.
pullTriggersMu
.
RLock
()
defer
db
.
pullTriggersMu
.
RUnlock
()
triggers
,
ok
:=
db
.
pullTriggers
[
bin
]
if
!
ok
{
return
}
for
_
,
t
:=
range
triggers
{
select
{
case
t
<-
struct
{}{}
:
default
:
}
}
}
// addressInBin returns an address that is in a specific
// proximity order bin from database base key.
func
(
db
*
DB
)
addressInBin
(
bin
uint8
)
(
addr
chunk
.
Address
)
{
addr
=
append
([]
byte
(
nil
),
db
.
baseKey
...
)
b
:=
bin
/
8
addr
[
b
]
=
addr
[
b
]
^
(
1
<<
(
7
-
bin
%
8
))
return
addr
}
pkg/storage/localstore/subscription_pull_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
)
// TestDB_SubscribePull_first is a regression test for the first=false (from-1) bug
// The bug was that `first=false` was not behind an if-condition `if count > 0`. This resulted in chunks being missed, when
// the subscription is established before the chunk is actually uploaded. For example if a subscription is established with since=49,
// which means that the `SubscribePull` method should return chunk with BinID=49 via the channel, and the chunk for BinID=49 is uploaded,
// after the subscription, then it would have been skipped, where the correct behaviour is to not skip it and return it via the channel.
func
TestDB_SubscribePull_first
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
// prepopulate database with some chunks
// before the subscription
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
100
)
// any bin should do the trick
bin
:=
uint8
(
1
)
chunksInGivenBin
:=
uint64
(
len
(
addrs
[
bin
]))
errc
:=
make
(
chan
error
)
since
:=
chunksInGivenBin
+
1
go
func
()
{
ch
,
stop
:=
db
.
SubscribePull
(
context
.
TODO
(),
bin
,
since
,
0
)
defer
stop
()
chnk
:=
<-
ch
if
chnk
.
BinID
!=
since
{
errc
<-
fmt
.
Errorf
(
"expected chunk.BinID to be %v , but got %v"
,
since
,
chnk
.
BinID
)
}
else
{
errc
<-
nil
}
}()
time
.
Sleep
(
100
*
time
.
Millisecond
)
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
100
)
err
:=
<-
errc
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
// TestDB_SubscribePull uploads some chunks before and after
// pull syncing subscription is created and validates if
// all addresses are received in the right order
// for expected proximity order bins.
func
TestDB_SubscribePull
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
// prepopulate database with some chunks
// before the subscription
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
10
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
0
,
0
)
defer
stop
()
// receive and validate addresses from the subscription
go
readPullSubscriptionBin
(
ctx
,
db
,
bin
,
ch
,
addrs
,
&
addrsMu
,
errChan
)
}
// upload some chunks just after subscribe
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
5
)
time
.
Sleep
(
200
*
time
.
Millisecond
)
// upload some chunks after some short time
// to ensure that subscription will include them
// in a dynamic environment
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
3
)
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
)
}
// TestDB_SubscribePull_multiple uploads chunks before and after
// multiple pull syncing subscriptions are created and
// validates if all addresses are received in the right order
// for expected proximity order bins.
func
TestDB_SubscribePull_multiple
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
// prepopulate database with some chunks
// before the subscription
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
10
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
subsCount
:=
10
// start a number of subscriptions
// that all of them will write every address error to errChan
for
j
:=
0
;
j
<
subsCount
;
j
++
{
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
0
,
0
)
defer
stop
()
// receive and validate addresses from the subscription
go
readPullSubscriptionBin
(
ctx
,
db
,
bin
,
ch
,
addrs
,
&
addrsMu
,
errChan
)
}
}
// upload some chunks just after subscribe
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
5
)
time
.
Sleep
(
200
*
time
.
Millisecond
)
// upload some chunks after some short time
// to ensure that subscription will include them
// in a dynamic environment
uploadRandomChunksBin
(
t
,
db
,
addrs
,
&
addrsMu
,
&
wantedChunksCount
,
3
)
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
*
subsCount
)
}
// TestDB_SubscribePull_since uploads chunks before and after
// pull syncing subscriptions are created with a since argument
// and validates if all expected addresses are received in the
// right order for expected proximity order bins.
func
TestDB_SubscribePull_since
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
binIDCounter
:=
make
(
map
[
uint8
]
uint64
)
var
binIDCounterMu
sync
.
RWMutex
uploadRandomChunks
:=
func
(
count
int
,
wanted
bool
)
(
first
map
[
uint8
]
uint64
)
{
addrsMu
.
Lock
()
defer
addrsMu
.
Unlock
()
first
=
make
(
map
[
uint8
]
uint64
)
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
binIDCounterMu
.
RLock
()
binIDCounter
[
bin
]
++
binIDCounterMu
.
RUnlock
()
if
wanted
{
if
_
,
ok
:=
addrs
[
bin
];
!
ok
{
addrs
[
bin
]
=
make
([]
chunk
.
Address
,
0
)
}
addrs
[
bin
]
=
append
(
addrs
[
bin
],
ch
.
Address
())
wantedChunksCount
++
if
_
,
ok
:=
first
[
bin
];
!
ok
{
first
[
bin
]
=
binIDCounter
[
bin
]
}
}
}
return
first
}
// prepopulate database with some chunks
// before the subscription
uploadRandomChunks
(
30
,
false
)
first
:=
uploadRandomChunks
(
25
,
true
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
since
,
ok
:=
first
[
bin
]
if
!
ok
{
continue
}
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
since
,
0
)
defer
stop
()
// receive and validate addresses from the subscription
go
readPullSubscriptionBin
(
ctx
,
db
,
bin
,
ch
,
addrs
,
&
addrsMu
,
errChan
)
}
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
)
}
// TestDB_SubscribePull_until uploads chunks before and after
// pull syncing subscriptions are created with an until argument
// and validates if all expected addresses are received in the
// right order for expected proximity order bins.
func
TestDB_SubscribePull_until
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
binIDCounter
:=
make
(
map
[
uint8
]
uint64
)
var
binIDCounterMu
sync
.
RWMutex
uploadRandomChunks
:=
func
(
count
int
,
wanted
bool
)
(
last
map
[
uint8
]
uint64
)
{
addrsMu
.
Lock
()
defer
addrsMu
.
Unlock
()
last
=
make
(
map
[
uint8
]
uint64
)
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
if
_
,
ok
:=
addrs
[
bin
];
!
ok
{
addrs
[
bin
]
=
make
([]
chunk
.
Address
,
0
)
}
if
wanted
{
addrs
[
bin
]
=
append
(
addrs
[
bin
],
ch
.
Address
())
wantedChunksCount
++
}
binIDCounterMu
.
RLock
()
binIDCounter
[
bin
]
++
binIDCounterMu
.
RUnlock
()
last
[
bin
]
=
binIDCounter
[
bin
]
}
return
last
}
// prepopulate database with some chunks
// before the subscription
last
:=
uploadRandomChunks
(
30
,
true
)
uploadRandomChunks
(
25
,
false
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
until
,
ok
:=
last
[
bin
]
if
!
ok
{
continue
}
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
0
,
until
)
defer
stop
()
// receive and validate addresses from the subscription
go
readPullSubscriptionBin
(
ctx
,
db
,
bin
,
ch
,
addrs
,
&
addrsMu
,
errChan
)
}
// upload some chunks just after subscribe
uploadRandomChunks
(
15
,
false
)
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
)
}
// TestDB_SubscribePull_sinceAndUntil uploads chunks before and
// after pull syncing subscriptions are created with since
// and until arguments, and validates if all expected addresses
// are received in the right order for expected proximity order bins.
func
TestDB_SubscribePull_sinceAndUntil
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
var
addrsMu
sync
.
Mutex
var
wantedChunksCount
int
binIDCounter
:=
make
(
map
[
uint8
]
uint64
)
var
binIDCounterMu
sync
.
RWMutex
uploadRandomChunks
:=
func
(
count
int
,
wanted
bool
)
(
last
map
[
uint8
]
uint64
)
{
addrsMu
.
Lock
()
defer
addrsMu
.
Unlock
()
last
=
make
(
map
[
uint8
]
uint64
)
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
if
_
,
ok
:=
addrs
[
bin
];
!
ok
{
addrs
[
bin
]
=
make
([]
chunk
.
Address
,
0
)
}
if
wanted
{
addrs
[
bin
]
=
append
(
addrs
[
bin
],
ch
.
Address
())
wantedChunksCount
++
}
binIDCounterMu
.
RLock
()
binIDCounter
[
bin
]
++
binIDCounterMu
.
RUnlock
()
last
[
bin
]
=
binIDCounter
[
bin
]
}
return
last
}
// all chunks from upload1 are not expected
// as upload1 chunk is used as since for subscriptions
upload1
:=
uploadRandomChunks
(
100
,
false
)
// all chunks from upload2 are expected
// as upload2 chunk is used as until for subscriptions
upload2
:=
uploadRandomChunks
(
100
,
true
)
// upload some chunks before subscribe but after
// wanted chunks
uploadRandomChunks
(
8
,
false
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
since
,
ok
:=
upload1
[
bin
]
if
ok
{
// start from the next uploaded chunk
since
++
}
until
,
ok
:=
upload2
[
bin
]
if
!
ok
{
// no chunks un this bin uploaded in the upload2
// skip this bin from testing
continue
}
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
since
,
until
)
defer
stop
()
// receive and validate addresses from the subscription
go
readPullSubscriptionBin
(
ctx
,
db
,
bin
,
ch
,
addrs
,
&
addrsMu
,
errChan
)
}
// upload some chunks just after subscribe
uploadRandomChunks
(
15
,
false
)
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
)
}
// TestDB_SubscribePull_rangeOnRemovedChunks performs a test:
// - uploads a number of chunks
// - removes first half of chunks for every bin
// - subscribes to a range that is within removed chunks,
// but before the chunks that are left
// - validates that no chunks are received on subscription channel
func
TestDB_SubscribePull_rangeOnRemovedChunks
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
// keeps track of available chunks in the database
// per bin with their bin ids
chunks
:=
make
(
map
[
uint8
][]
chunk
.
Descriptor
)
// keeps track of latest bin id for every bin
binIDCounter
:=
make
(
map
[
uint8
]
uint64
)
// upload chunks to populate bins from start
// bin ids start from 1
const
chunkCount
=
1000
for
i
:=
0
;
i
<
chunkCount
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
binIDCounter
[
bin
]
++
binID
:=
binIDCounter
[
bin
]
if
_
,
ok
:=
chunks
[
bin
];
!
ok
{
chunks
[
bin
]
=
make
([]
chunk
.
Descriptor
,
0
)
}
chunks
[
bin
]
=
append
(
chunks
[
bin
],
chunk
.
Descriptor
{
Address
:
ch
.
Address
(),
BinID
:
binID
,
})
}
// remove first half of the chunks in every bin
for
bin
:=
range
chunks
{
count
:=
len
(
chunks
[
bin
])
for
i
:=
0
;
i
<
count
/
2
;
i
++
{
d
:=
chunks
[
bin
][
0
]
if
err
:=
db
.
Set
(
context
.
Background
(),
chunk
.
ModeSetRemove
,
d
.
Address
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
[
bin
]
=
chunks
[
bin
][
1
:
]
}
}
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// signals that there were valid bins for this check to ensure test validity
var
checkedBins
int
// subscribe to every bin and validate returned values
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
// do not subscribe to bins that do not have chunks
if
len
(
chunks
[
bin
])
==
0
{
continue
}
// subscribe from start of the bin index
var
since
uint64
// subscribe until the first available chunk in bin,
// but not for it
until
:=
chunks
[
bin
][
0
]
.
BinID
-
1
if
until
==
0
{
// ignore this bin if it has only one chunk left
continue
}
ch
,
stop
:=
db
.
SubscribePull
(
ctx
,
bin
,
since
,
until
)
defer
stop
()
// the returned channel should be closed
// because no chunks should be provided
select
{
case
d
,
ok
:=
<-
ch
:
if
!
ok
{
// this is expected for successful case
break
}
if
d
.
BinID
>
until
{
t
.
Errorf
(
"got %v for bin %v, subscribed until bin id %v"
,
d
.
BinID
,
bin
,
until
)
}
case
<-
ctx
.
Done
()
:
t
.
Error
(
ctx
.
Err
())
}
// mark that the check is performed
checkedBins
++
}
// check that test performed at least one validation
if
checkedBins
==
0
{
t
.
Fatal
(
"test did not perform any checks"
)
}
}
// uploadRandomChunksBin uploads random chunks to database and adds them to
// the map of addresses ber bin.
func
uploadRandomChunksBin
(
t
*
testing
.
T
,
db
*
DB
,
addrs
map
[
uint8
][]
chunk
.
Address
,
addrsMu
*
sync
.
Mutex
,
wantedChunksCount
*
int
,
count
int
)
{
addrsMu
.
Lock
()
defer
addrsMu
.
Unlock
()
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
if
_
,
ok
:=
addrs
[
bin
];
!
ok
{
addrs
[
bin
]
=
make
([]
chunk
.
Address
,
0
)
}
addrs
[
bin
]
=
append
(
addrs
[
bin
],
ch
.
Address
())
*
wantedChunksCount
++
}
}
// readPullSubscriptionBin is a helper function that reads all chunk.Descriptors from a channel and
// sends error to errChan, even if it is nil, to count the number of chunk.Descriptors
// returned by the channel.
func
readPullSubscriptionBin
(
ctx
context
.
Context
,
db
*
DB
,
bin
uint8
,
ch
<-
chan
chunk
.
Descriptor
,
addrs
map
[
uint8
][]
chunk
.
Address
,
addrsMu
*
sync
.
Mutex
,
errChan
chan
error
)
{
var
i
int
// address index
for
{
select
{
case
got
,
ok
:=
<-
ch
:
if
!
ok
{
return
}
var
err
error
addrsMu
.
Lock
()
if
i
+
1
>
len
(
addrs
[
bin
])
{
err
=
fmt
.
Errorf
(
"got more chunk addresses %v, then expected %v, for bin %v"
,
i
+
1
,
len
(
addrs
[
bin
]),
bin
)
}
else
{
addr
:=
addrs
[
bin
][
i
]
if
!
bytes
.
Equal
(
got
.
Address
,
addr
)
{
err
=
fmt
.
Errorf
(
"got chunk bin id %v in bin %v %v, want %v"
,
i
,
bin
,
got
.
Address
.
Hex
(),
addr
.
Hex
())
}
else
{
var
want
shed
.
Item
want
,
err
=
db
.
retrievalDataIndex
.
Get
(
shed
.
Item
{
Address
:
addr
,
})
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"got chunk (bin id %v in bin %v) from retrieval index %s: %v"
,
i
,
bin
,
addrs
[
bin
][
i
]
.
Hex
(),
err
)
}
else
{
if
got
.
BinID
!=
want
.
BinID
{
err
=
fmt
.
Errorf
(
"got chunk bin id %v in bin %v %v, want %v"
,
i
,
bin
,
got
,
want
)
}
}
}
}
addrsMu
.
Unlock
()
i
++
// send one and only one error per received address
select
{
case
errChan
<-
err
:
case
<-
ctx
.
Done
()
:
return
}
case
<-
ctx
.
Done
()
:
return
}
}
}
// checkErrChan expects the number of wantedChunksCount errors from errChan
// and calls t.Error for the ones that are not nil.
func
checkErrChan
(
ctx
context
.
Context
,
t
*
testing
.
T
,
errChan
chan
error
,
wantedChunksCount
int
)
{
t
.
Helper
()
for
i
:=
0
;
i
<
wantedChunksCount
;
i
++
{
select
{
case
err
:=
<-
errChan
:
if
err
!=
nil
{
t
.
Error
(
err
)
}
case
<-
ctx
.
Done
()
:
t
.
Fatal
(
ctx
.
Err
())
}
}
}
// TestDB_LastPullSubscriptionBinID validates that LastPullSubscriptionBinID
// is returning the last chunk descriptor for proximity order bins by
// doing a few rounds of chunk uploads.
func
TestDB_LastPullSubscriptionBinID
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
(
map
[
uint8
][]
chunk
.
Address
)
binIDCounter
:=
make
(
map
[
uint8
]
uint64
)
var
binIDCounterMu
sync
.
RWMutex
last
:=
make
(
map
[
uint8
]
uint64
)
// do a few rounds of uploads and check if
// last pull subscription chunk is correct
for
_
,
count
:=
range
[]
int
{
1
,
3
,
10
,
11
,
100
,
120
}
{
// upload
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
bin
:=
db
.
po
(
ch
.
Address
())
if
_
,
ok
:=
addrs
[
bin
];
!
ok
{
addrs
[
bin
]
=
make
([]
chunk
.
Address
,
0
)
}
addrs
[
bin
]
=
append
(
addrs
[
bin
],
ch
.
Address
())
binIDCounterMu
.
RLock
()
binIDCounter
[
bin
]
++
binIDCounterMu
.
RUnlock
()
last
[
bin
]
=
binIDCounter
[
bin
]
}
// check
for
bin
:=
uint8
(
0
);
bin
<=
uint8
(
chunk
.
MaxPO
);
bin
++
{
want
,
ok
:=
last
[
bin
]
got
,
err
:=
db
.
LastPullSubscriptionBinID
(
bin
)
if
ok
{
if
err
!=
nil
{
t
.
Errorf
(
"got unexpected error value %v"
,
err
)
}
}
if
got
!=
want
{
t
.
Errorf
(
"got last bin id %v, want %v"
,
got
,
want
)
}
}
}
}
// TestAddressInBin validates that function addressInBin
// returns a valid address for every proximity order bin.
func
TestAddressInBin
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
for
po
:=
uint8
(
0
);
po
<
chunk
.
MaxPO
;
po
++
{
addr
:=
db
.
addressInBin
(
po
)
got
:=
db
.
po
(
addr
)
if
got
!=
po
{
t
.
Errorf
(
"got po %v, want %v"
,
got
,
po
)
}
}
}
pkg/storage/localstore/subscription_push.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"context"
"fmt"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethersphere/swarm/chunk"
"github.com/ethersphere/swarm/shed"
)
// SubscribePush returns a channel that provides storage chunks with ordering from push syncing index.
// Returned stop function will terminate current and further iterations, and also it will close
// the returned channel without any errors. Make sure that you check the second returned parameter
// from the channel to stop iteration when its value is false.
func
(
db
*
DB
)
SubscribePush
(
ctx
context
.
Context
)
(
c
<-
chan
chunk
.
Chunk
,
stop
func
())
{
metricName
:=
"localstore/SubscribePush"
metrics
.
GetOrRegisterCounter
(
metricName
,
nil
)
.
Inc
(
1
)
chunks
:=
make
(
chan
chunk
.
Chunk
)
trigger
:=
make
(
chan
struct
{},
1
)
db
.
pushTriggersMu
.
Lock
()
db
.
pushTriggers
=
append
(
db
.
pushTriggers
,
trigger
)
db
.
pushTriggersMu
.
Unlock
()
// send signal for the initial iteration
trigger
<-
struct
{}{}
stopChan
:=
make
(
chan
struct
{})
var
stopChanOnce
sync
.
Once
db
.
subscritionsWG
.
Add
(
1
)
go
func
()
{
defer
db
.
subscritionsWG
.
Done
()
defer
metrics
.
GetOrRegisterCounter
(
metricName
+
"/done"
,
nil
)
.
Inc
(
1
)
// close the returned chunkInfo channel at the end to
// signal that the subscription is done
defer
close
(
chunks
)
// sinceItem is the Item from which the next iteration
// should start. The first iteration starts from the first Item.
var
sinceItem
*
shed
.
Item
for
{
select
{
case
<-
trigger
:
// iterate until:
// - last index Item is reached
// - subscription stop is called
// - context is done
metrics
.
GetOrRegisterCounter
(
metricName
+
"/iter"
,
nil
)
.
Inc
(
1
)
iterStart
:=
time
.
Now
()
var
count
int
err
:=
db
.
pushIndex
.
Iterate
(
func
(
item
shed
.
Item
)
(
stop
bool
,
err
error
)
{
// get chunk data
dataItem
,
err
:=
db
.
retrievalDataIndex
.
Get
(
item
)
if
err
!=
nil
{
return
true
,
err
}
select
{
case
chunks
<-
chunk
.
NewChunk
(
dataItem
.
Address
,
dataItem
.
Data
)
.
WithTagID
(
item
.
Tag
)
:
count
++
// set next iteration start item
// when its chunk is successfully sent to channel
sinceItem
=
&
item
log
.
Trace
(
"subscribe.push"
,
"ref"
,
fmt
.
Sprintf
(
"%x"
,
sinceItem
.
Address
),
"binid"
,
sinceItem
.
BinID
)
return
false
,
nil
case
<-
stopChan
:
// gracefully stop the iteration
// on stop
return
true
,
nil
case
<-
db
.
close
:
// gracefully stop the iteration
// on database close
return
true
,
nil
case
<-
ctx
.
Done
()
:
return
true
,
ctx
.
Err
()
}
},
&
shed
.
IterateOptions
{
StartFrom
:
sinceItem
,
// sinceItem was sent as the last Address in the previous
// iterator call, skip it in this one
SkipStartFromItem
:
true
,
})
totalTimeMetric
(
metricName
+
"/iter"
,
iterStart
)
if
err
!=
nil
{
metrics
.
GetOrRegisterCounter
(
metricName
+
"/iter/error"
,
nil
)
.
Inc
(
1
)
log
.
Error
(
"localstore push subscription iteration"
,
"err"
,
err
)
return
}
case
<-
stopChan
:
// terminate the subscription
// on stop
return
case
<-
db
.
close
:
// terminate the subscription
// on database close
return
case
<-
ctx
.
Done
()
:
err
:=
ctx
.
Err
()
if
err
!=
nil
{
log
.
Error
(
"localstore push subscription"
,
"err"
,
err
)
}
return
}
}
}()
stop
=
func
()
{
stopChanOnce
.
Do
(
func
()
{
close
(
stopChan
)
})
db
.
pushTriggersMu
.
Lock
()
defer
db
.
pushTriggersMu
.
Unlock
()
for
i
,
t
:=
range
db
.
pushTriggers
{
if
t
==
trigger
{
db
.
pushTriggers
=
append
(
db
.
pushTriggers
[
:
i
],
db
.
pushTriggers
[
i
+
1
:
]
...
)
break
}
}
}
return
chunks
,
stop
}
// triggerPushSubscriptions is used internally for starting iterations
// on Push subscriptions. Whenever new item is added to the push index,
// this function should be called.
func
(
db
*
DB
)
triggerPushSubscriptions
()
{
db
.
pushTriggersMu
.
RLock
()
defer
db
.
pushTriggersMu
.
RUnlock
()
for
_
,
t
:=
range
db
.
pushTriggers
{
select
{
case
t
<-
struct
{}{}
:
default
:
}
}
}
pkg/storage/localstore/subscription_push_test.go
0 → 100644
View file @
26eea2bd
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
localstore
import
(
"bytes"
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/ethersphere/swarm/chunk"
)
// TestDB_SubscribePush uploads some chunks before and after
// push syncing subscription is created and validates if
// all addresses are received in the right order.
func
TestDB_SubscribePush
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
chunks
:=
make
([]
chunk
.
Chunk
,
0
)
var
chunksMu
sync
.
Mutex
uploadRandomChunks
:=
func
(
count
int
)
{
chunksMu
.
Lock
()
defer
chunksMu
.
Unlock
()
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chunks
=
append
(
chunks
,
ch
)
}
}
// prepopulate database with some chunks
// before the subscription
uploadRandomChunks
(
10
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
ch
,
stop
:=
db
.
SubscribePush
(
ctx
)
defer
stop
()
// receive and validate addresses from the subscription
go
func
()
{
var
i
int
// address index
for
{
select
{
case
got
,
ok
:=
<-
ch
:
if
!
ok
{
return
}
chunksMu
.
Lock
()
want
:=
chunks
[
i
]
chunksMu
.
Unlock
()
var
err
error
if
!
bytes
.
Equal
(
got
.
Data
(),
want
.
Data
())
{
err
=
fmt
.
Errorf
(
"got chunk %v data %x, want %x"
,
i
,
got
.
Data
(),
want
.
Data
())
}
if
!
bytes
.
Equal
(
got
.
Address
(),
want
.
Address
())
{
err
=
fmt
.
Errorf
(
"got chunk %v address %s, want %s"
,
i
,
got
.
Address
()
.
Hex
(),
want
.
Address
()
.
Hex
())
}
i
++
// send one and only one error per received address
select
{
case
errChan
<-
err
:
case
<-
ctx
.
Done
()
:
return
}
case
<-
ctx
.
Done
()
:
return
}
}
}()
// upload some chunks just after subscribe
uploadRandomChunks
(
5
)
time
.
Sleep
(
200
*
time
.
Millisecond
)
// upload some chunks after some short time
// to ensure that subscription will include them
// in a dynamic environment
uploadRandomChunks
(
3
)
checkErrChan
(
ctx
,
t
,
errChan
,
len
(
chunks
))
}
// TestDB_SubscribePush_multiple uploads chunks before and after
// multiple push syncing subscriptions are created and
// validates if all addresses are received in the right order.
func
TestDB_SubscribePush_multiple
(
t
*
testing
.
T
)
{
db
,
cleanupFunc
:=
newTestDB
(
t
,
nil
)
defer
cleanupFunc
()
addrs
:=
make
([]
chunk
.
Address
,
0
)
var
addrsMu
sync
.
Mutex
uploadRandomChunks
:=
func
(
count
int
)
{
addrsMu
.
Lock
()
defer
addrsMu
.
Unlock
()
for
i
:=
0
;
i
<
count
;
i
++
{
ch
:=
generateTestRandomChunk
()
_
,
err
:=
db
.
Put
(
context
.
Background
(),
chunk
.
ModePutUpload
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addrs
=
append
(
addrs
,
ch
.
Address
())
}
}
// prepopulate database with some chunks
// before the subscription
uploadRandomChunks
(
10
)
// set a timeout on subscription
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
// collect all errors from validating addresses, even nil ones
// to validate the number of addresses received by the subscription
errChan
:=
make
(
chan
error
)
subsCount
:=
10
// start a number of subscriptions
// that all of them will write every addresses error to errChan
for
j
:=
0
;
j
<
subsCount
;
j
++
{
ch
,
stop
:=
db
.
SubscribePush
(
ctx
)
defer
stop
()
// receive and validate addresses from the subscription
go
func
(
j
int
)
{
var
i
int
// address index
for
{
select
{
case
got
,
ok
:=
<-
ch
:
if
!
ok
{
return
}
addrsMu
.
Lock
()
want
:=
addrs
[
i
]
addrsMu
.
Unlock
()
var
err
error
if
!
bytes
.
Equal
(
got
.
Address
(),
want
)
{
err
=
fmt
.
Errorf
(
"got chunk %v address on subscription %v %s, want %s"
,
i
,
j
,
got
,
want
)
}
i
++
// send one and only one error per received address
select
{
case
errChan
<-
err
:
case
<-
ctx
.
Done
()
:
return
}
case
<-
ctx
.
Done
()
:
return
}
}
}(
j
)
}
// upload some chunks just after subscribe
uploadRandomChunks
(
5
)
time
.
Sleep
(
200
*
time
.
Millisecond
)
// upload some chunks after some short time
// to ensure that subscription will include them
// in a dynamic environment
uploadRandomChunks
(
3
)
// number of addresses received by all subscriptions
wantedChunksCount
:=
len
(
addrs
)
*
subsCount
checkErrChan
(
ctx
,
t
,
errChan
,
wantedChunksCount
)
}
pkg/storage/localstore/testdata/sanctuary/000002.log
0 → 100644
View file @
26eea2bd
File added
pkg/storage/localstore/testdata/sanctuary/CURRENT
0 → 100644
View file @
26eea2bd
MANIFEST-000003
pkg/storage/localstore/testdata/sanctuary/CURRENT.bak
0 → 100644
View file @
26eea2bd
MANIFEST-000000
pkg/storage/localstore/testdata/sanctuary/LOCK
0 → 100644
View file @
26eea2bd
pkg/storage/localstore/testdata/sanctuary/LOG
0 → 100644
View file @
26eea2bd
=============== Nov 13, 2019 (+0530) ===============
15:55:56.807910 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
15:55:56.810616 db@open opening
15:55:56.810899 version@stat F·[] S·0B[] Sc·[]
15:55:56.812573 db@janitor F·2 G·0
15:55:56.812586 db@open done T·1.947185ms
15:55:56.812598 db@close closing
15:55:56.812664 db@close done T·62.171µs
=============== Nov 13, 2019 (+0530) ===============
15:55:56.812745 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
15:55:56.812833 version@stat F·[] S·0B[] Sc·[]
15:55:56.812845 db@open opening
15:55:56.812875 journal@recovery F·1
15:55:56.812980 journal@recovery recovering @1
15:55:56.813117 version@stat F·[] S·0B[] Sc·[]
15:55:56.817949 db@janitor F·2 G·0
15:55:56.817966 db@open done T·5.117043ms
15:55:58.621297 db@close closing
15:55:58.621392 db@close done T·93.745µs
pkg/storage/localstore/testdata/sanctuary/MANIFEST-000003
0 → 100644
View file @
26eea2bd
File added
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment