Skip to content

Commit

Permalink
[FAB-1653] Enable human-readable byte sizes in config
Browse files Browse the repository at this point in the history
Byte sizes can be specified with the following case
insensitive suffixes:
 - 'k', 'kb', 'm', 'mb', 'g', 'gb'

Change-Id: I36c3fd424ed52794562a6b50e7a3d400f053c52a
Signed-off-by: Luis Sanchez <sanchezl@us.ibm.com>
  • Loading branch information
Luis Sanchez committed Jan 16, 2017
1 parent 4f90cd9 commit 972ef53
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 3 deletions.
71 changes: 71 additions & 0 deletions orderer/localconfig/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,77 @@ func TestEnvSlice(t *testing.T) {
}
}

type testByteSize struct {
Inner struct {
ByteSize uint32
}
}

func TestByteSize(t *testing.T) {
config := viper.New()
config.SetConfigType("yaml")

testCases := []struct {
data string
expected uint32
}{
{"", 0},
{"42", 42},
{"42k", 42 * 1024},
{"42kb", 42 * 1024},
{"42K", 42 * 1024},
{"42KB", 42 * 1024},
{"42 K", 42 * 1024},
{"42 KB", 42 * 1024},
{"42m", 42 * 1024 * 1024},
{"42mb", 42 * 1024 * 1024},
{"42M", 42 * 1024 * 1024},
{"42MB", 42 * 1024 * 1024},
{"42 M", 42 * 1024 * 1024},
{"42 MB", 42 * 1024 * 1024},
{"3g", 3 * 1024 * 1024 * 1024},
{"3gb", 3 * 1024 * 1024 * 1024},
{"3G", 3 * 1024 * 1024 * 1024},
{"3GB", 3 * 1024 * 1024 * 1024},
{"3 G", 3 * 1024 * 1024 * 1024},
{"3 GB", 3 * 1024 * 1024 * 1024},
}

for _, tc := range testCases {
t.Run(tc.data, func(t *testing.T) {
data := fmt.Sprintf("---\nInner:\n ByteSize: %s", tc.data)
err := config.ReadConfig(bytes.NewReader([]byte(data)))
if err != nil {
t.Fatalf("Error reading config: %s", err)
}
var uconf testByteSize
err = ExactWithDateUnmarshal(config, &uconf)
if err != nil {
t.Fatalf("Failed to unmarshal with: %s", err)
}
if uconf.Inner.ByteSize != tc.expected {
t.Fatalf("Did not get back the right byte size, expeced: %v got %v", tc.expected, uconf.Inner.ByteSize)
}
})
}
}

func TestByteSizeOverflow(t *testing.T) {
config := viper.New()
config.SetConfigType("yaml")

data := "---\nInner:\n ByteSize: 4GB"
err := config.ReadConfig(bytes.NewReader([]byte(data)))
if err != nil {
t.Fatalf("Error reading config: %s", err)
}
var uconf testByteSize
err = ExactWithDateUnmarshal(config, &uconf)
if err == nil {
t.Fatalf("Should have failed to unmarshal")
}
}

// TestEnvInnerVar verifies that with the Unmarshal function that
// the environmental overrides still work on internal vars. This was
// a bug in the original viper implementation that is worked around in
Expand Down
44 changes: 43 additions & 1 deletion orderer/localconfig/config_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ limitations under the License.
package config

import (
"fmt"
"math"
"reflect"
"regexp"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -83,6 +87,41 @@ func customDecodeHook() mapstructure.DecodeHookFunc {
}
}

func byteSizeDecodeHook() mapstructure.DecodeHookFunc {
return func(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) {
if f != reflect.String || t != reflect.Uint32 {
return data, nil
}
raw := data.(string)
if raw == "" {
return data, nil
}
var re = regexp.MustCompile(`^(?P<size>[0-9]+)\s*(?i)(?P<unit>(k|m|g))b?$`)
if re.MatchString(raw) {
size, err := strconv.ParseUint(re.ReplaceAllString(raw, "${size}"), 0, 64)
if err != nil {
return data, nil
}
unit := re.ReplaceAllString(raw, "${unit}")
switch strings.ToLower(unit) {
case "g":
size = size << 10
fallthrough
case "m":
size = size << 10
fallthrough
case "k":
size = size << 10
}
if size > math.MaxUint32 {
return size, fmt.Errorf("value '%s' overflows uint32", raw)
}
return size, nil
}
return data, nil
}
}

// ExactWithDateUnmarshal is intended to unmarshal a config file into a structure
// producing error when extraneous variables are introduced and supporting
// the time.Duration type
Expand All @@ -96,7 +135,10 @@ func ExactWithDateUnmarshal(v *viper.Viper, output interface{}) error {
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
DecodeHook: customDecodeHook(),
DecodeHook: mapstructure.ComposeDecodeHookFunc(
customDecodeHook(),
byteSizeDecodeHook(),
),
}

decoder, err := mapstructure.NewDecoder(config)
Expand Down
4 changes: 2 additions & 2 deletions orderer/orderer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ Genesis:

# Absolute Max Bytes: The absolute maximum number of bytes allowed for
# the serialized messages in a batch.
AbsoluteMaxBytes: 100000000
AbsoluteMaxBytes: 99 MB

# Preferred Max Bytes: The preferred maximum number of bytes allowed for
# the serialized messages in a batch. A message larger than the preferred
# max bytes will result in a batch larger than preferred max bytes.
PreferredMaxBytes: 524288
PreferredMaxBytes: 512 KB

0 comments on commit 972ef53

Please sign in to comment.