From d9bb25b4b94fbcd93280f8cb43018bff5916b9bd Mon Sep 17 00:00:00 2001 From: Maximillian von Briesen Date: Thu, 31 Oct 2019 15:04:33 -0400 Subject: [PATCH] satellite/metainfo: support a wider range of values for RS.Total in satellite metainfo validation (#3431) change uplink RS default configuration from 130 to 95 --- internal/testplanet/satellite.go | 17 ++++---- lib/uplink/project.go | 2 +- satellite/metainfo/config.go | 17 ++++---- satellite/metainfo/metainfo_test.go | 43 +++++++++++++++++++++ satellite/metainfo/validation.go | 8 ++-- scripts/testdata/satellite-config.yaml.lock | 7 +++- uplink/config.go | 2 +- 7 files changed, 73 insertions(+), 23 deletions(-) diff --git a/internal/testplanet/satellite.go b/internal/testplanet/satellite.go index be375e9b6..de88c3f0a 100644 --- a/internal/testplanet/satellite.go +++ b/internal/testplanet/satellite.go @@ -290,14 +290,15 @@ func (planet *Planet) newSatellites(count int) ([]*SatelliteSystem, error) { MaxCommitInterval: 1 * time.Hour, Overlay: true, RS: metainfo.RSConfig{ - MaxSegmentSize: 64 * memory.MiB, - MaxBufferMem: memory.Size(256), - ErasureShareSize: memory.Size(256), - MinThreshold: (planet.config.StorageNodeCount * 1 / 5), - RepairThreshold: (planet.config.StorageNodeCount * 2 / 5), - SuccessThreshold: (planet.config.StorageNodeCount * 3 / 5), - MaxThreshold: (planet.config.StorageNodeCount * 4 / 5), - Validate: false, + MaxSegmentSize: 64 * memory.MiB, + MaxBufferMem: memory.Size(256), + ErasureShareSize: memory.Size(256), + MinThreshold: (planet.config.StorageNodeCount * 1 / 5), + RepairThreshold: (planet.config.StorageNodeCount * 2 / 5), + SuccessThreshold: (planet.config.StorageNodeCount * 3 / 5), + MinTotalThreshold: (planet.config.StorageNodeCount * 4 / 5), + MaxTotalThreshold: (planet.config.StorageNodeCount * 4 / 5), + Validate: false, }, Loop: metainfo.LoopConfig{ CoalesceDuration: 1 * time.Second, diff --git a/lib/uplink/project.go b/lib/uplink/project.go index 126656b28..ca65ccf0f 100644 --- a/lib/uplink/project.go +++ b/lib/uplink/project.go @@ -79,7 +79,7 @@ func (cfg *BucketConfig) setDefaults() { cfg.Volatile.RedundancyScheme.OptimalShares = 80 } if cfg.Volatile.RedundancyScheme.TotalShares == 0 { - cfg.Volatile.RedundancyScheme.TotalShares = 130 + cfg.Volatile.RedundancyScheme.TotalShares = 95 } if cfg.Volatile.RedundancyScheme.ShareSize == 0 { cfg.Volatile.RedundancyScheme.ShareSize = 256 * memory.B.Int32() diff --git a/satellite/metainfo/config.go b/satellite/metainfo/config.go index 5d7f7acfa..9394e717d 100644 --- a/satellite/metainfo/config.go +++ b/satellite/metainfo/config.go @@ -23,14 +23,15 @@ const ( // RSConfig is a configuration struct that keeps details about default // redundancy strategy information type RSConfig struct { - MaxSegmentSize memory.Size `help:"maximum segment size" default:"64MiB"` - MaxBufferMem memory.Size `help:"maximum buffer memory to be allocated for read buffers" default:"4MiB"` - ErasureShareSize memory.Size `help:"the size of each new erasure share in bytes" default:"256B"` - MinThreshold int `help:"the minimum pieces required to recover a segment. k." releaseDefault:"29" devDefault:"4"` - RepairThreshold int `help:"the minimum safe pieces before a repair is triggered. m." releaseDefault:"35" devDefault:"6"` - SuccessThreshold int `help:"the desired total pieces for a segment. o." releaseDefault:"80" devDefault:"8"` - MaxThreshold int `help:"the largest amount of pieces to encode to. n." releaseDefault:"130" devDefault:"10"` - Validate bool `help:"validate redundancy scheme configuration" default:"true"` + MaxSegmentSize memory.Size `help:"maximum segment size" default:"64MiB"` + MaxBufferMem memory.Size `help:"maximum buffer memory to be allocated for read buffers" default:"4MiB"` + ErasureShareSize memory.Size `help:"the size of each new erasure share in bytes" default:"256B"` + MinThreshold int `help:"the minimum pieces required to recover a segment. k." releaseDefault:"29" devDefault:"4"` + RepairThreshold int `help:"the minimum safe pieces before a repair is triggered. m." releaseDefault:"35" devDefault:"6"` + SuccessThreshold int `help:"the desired total pieces for a segment. o." releaseDefault:"80" devDefault:"8"` + MinTotalThreshold int `help:"the largest amount of pieces to encode to. n (lower bound for validation)." releaseDefault:"95" devDefault:"10"` + MaxTotalThreshold int `help:"the largest amount of pieces to encode to. n (upper bound for validation)." releaseDefault:"130" devDefault:"10"` + Validate bool `help:"validate redundancy scheme configuration" default:"true"` } // Config is a configuration struct that is everything you need to start a metainfo diff --git a/satellite/metainfo/metainfo_test.go b/satellite/metainfo/metainfo_test.go index 98bd028dd..fdff18593 100644 --- a/satellite/metainfo/metainfo_test.go +++ b/satellite/metainfo/metainfo_test.go @@ -28,6 +28,7 @@ import ( "storj.io/storj/pkg/signing" "storj.io/storj/pkg/storj" "storj.io/storj/satellite" + "storj.io/storj/uplink" "storj.io/storj/uplink/eestream" "storj.io/storj/uplink/metainfo" ) @@ -1681,3 +1682,45 @@ func TestBatch(t *testing.T) { } }) } + +func TestValidateRS(t *testing.T) { + testplanet.Run(t, testplanet.Config{ + SatelliteCount: 1, StorageNodeCount: 6, UplinkCount: 1, + Reconfigure: testplanet.Reconfigure{ + Satellite: func(log *zap.Logger, index int, config *satellite.Config) { + config.Metainfo.RS.MinTotalThreshold = 4 + config.Metainfo.RS.MaxTotalThreshold = 5 + config.Metainfo.RS.Validate = true + }, + }, + }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { + ul := planet.Uplinks[0] + satellite := planet.Satellites[0] + + testData := testrand.Bytes(8 * memory.KiB) + rs := &uplink.RSConfig{ + MinThreshold: 1, + RepairThreshold: 2, + SuccessThreshold: 3, + MaxThreshold: 3, + } + // test below permitted total value + err := ul.UploadWithConfig(ctx, satellite, rs, "testbucket", "test/path/below", testData) + require.Error(t, err) + + // test above permitted total value + rs.MaxThreshold = 6 + err = ul.UploadWithConfig(ctx, satellite, rs, "testbucket", "test/path/above", testData) + require.Error(t, err) + + // test minimum permitted total value + rs.MaxThreshold = 4 + err = ul.UploadWithConfig(ctx, satellite, rs, "testbucket", "test/path/min", testData) + require.NoError(t, err) + + // test maximum permitted total value + rs.MaxThreshold = 5 + err = ul.UploadWithConfig(ctx, satellite, rs, "testbucket", "test/path/max", testData) + require.NoError(t, err) + }) +} diff --git a/satellite/metainfo/validation.go b/satellite/metainfo/validation.go index efe80054a..788959147 100644 --- a/satellite/metainfo/validation.go +++ b/satellite/metainfo/validation.go @@ -343,15 +343,17 @@ func (endpoint *Endpoint) validateRedundancy(ctx context.Context, redundancy *pb if endpoint.requiredRSConfig.Validate { if endpoint.requiredRSConfig.ErasureShareSize.Int32() != redundancy.ErasureShareSize || - endpoint.requiredRSConfig.MaxThreshold != int(redundancy.Total) || + endpoint.requiredRSConfig.MinTotalThreshold > int(redundancy.Total) || + endpoint.requiredRSConfig.MaxTotalThreshold < int(redundancy.Total) || endpoint.requiredRSConfig.MinThreshold != int(redundancy.MinReq) || endpoint.requiredRSConfig.RepairThreshold != int(redundancy.RepairThreshold) || endpoint.requiredRSConfig.SuccessThreshold != int(redundancy.SuccessThreshold) { - return Error.New("provided redundancy scheme parameters not allowed: want [%d, %d, %d, %d, %d] got [%d, %d, %d, %d, %d]", + return Error.New("provided redundancy scheme parameters not allowed: want [%d, %d, %d, %d-%d, %d] got [%d, %d, %d, %d, %d]", endpoint.requiredRSConfig.MinThreshold, endpoint.requiredRSConfig.RepairThreshold, endpoint.requiredRSConfig.SuccessThreshold, - endpoint.requiredRSConfig.MaxThreshold, + endpoint.requiredRSConfig.MinTotalThreshold, + endpoint.requiredRSConfig.MaxTotalThreshold, endpoint.requiredRSConfig.ErasureShareSize.Int32(), redundancy.MinReq, diff --git a/scripts/testdata/satellite-config.yaml.lock b/scripts/testdata/satellite-config.yaml.lock index d4f5dd008..ae8149911 100644 --- a/scripts/testdata/satellite-config.yaml.lock +++ b/scripts/testdata/satellite-config.yaml.lock @@ -223,12 +223,15 @@ identity.key-path: /root/.local/share/storj/identity/satellite/identity.key # maximum segment size # metainfo.rs.max-segment-size: 64.0 MiB -# the largest amount of pieces to encode to. n. -# metainfo.rs.max-threshold: 130 +# the largest amount of pieces to encode to. n (upper bound for validation). +# metainfo.rs.max-total-threshold: 130 # the minimum pieces required to recover a segment. k. # metainfo.rs.min-threshold: 29 +# the largest amount of pieces to encode to. n (lower bound for validation). +# metainfo.rs.min-total-threshold: 95 + # the minimum safe pieces before a repair is triggered. m. # metainfo.rs.repair-threshold: 35 diff --git a/uplink/config.go b/uplink/config.go index fcc3e01e4..7bff70337 100644 --- a/uplink/config.go +++ b/uplink/config.go @@ -27,7 +27,7 @@ type RSConfig struct { MinThreshold int `help:"the minimum pieces required to recover a segment. k." releaseDefault:"29" devDefault:"4" hidden:"true"` RepairThreshold int `help:"the minimum safe pieces before a repair is triggered. m." releaseDefault:"35" devDefault:"6" hidden:"true"` SuccessThreshold int `help:"the desired total pieces for a segment. o." releaseDefault:"80" devDefault:"8" hidden:"true"` - MaxThreshold int `help:"the largest amount of pieces to encode to. n." releaseDefault:"130" devDefault:"10" hidden:"true"` + MaxThreshold int `help:"the largest amount of pieces to encode to. n." releaseDefault:"95" devDefault:"10" hidden:"true"` } // EncryptionConfig is a configuration struct that keeps details about