[#787] util/attributes: Reuse attribute struct to update parents list

Parser should reuse existing attributes from the cache to update list
of the parent links in it. Parent links should be unique.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2021-08-31 18:34:55 +03:00 committed by Alex Vanin
parent c1326efaf5
commit d8a04726ad
2 changed files with 51 additions and 10 deletions

View file

@ -48,7 +48,8 @@ func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute,
key := pair[0] key := pair[0]
value := pair[1] value := pair[1]
if at, ok := cache[key]; ok && at.Value() != value { attribute, present := cache[key]
if present && attribute.Value() != value {
return nil, errNonUniqueBucket return nil, errNonUniqueBucket
} }
@ -56,20 +57,26 @@ func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute,
return nil, errUnexpectedKey return nil, errUnexpectedKey
} }
// replace non-printable symbols with escaped symbols without escape character if !present {
key = replaceEscaping(key, true) // replace non-printable symbols with escaped symbols without escape character
value = replaceEscaping(value, true) key = replaceEscaping(key, true)
value = replaceEscaping(value, true)
attribute := netmap.NewNodeAttribute() attribute = netmap.NewNodeAttribute()
attribute.SetKey(key) attribute.SetKey(key)
attribute.SetValue(value) attribute.SetValue(value)
cache[key] = attribute
}
if parentKey != "" { if parentKey != "" {
attribute.SetParentKeys(parentKey) parentKeys := attribute.ParentKeys()
if !hasString(parentKeys, parentKey) {
attribute.SetParentKeys(append(parentKeys, parentKey)...)
}
} }
parentKey = key parentKey = key
cache[key] = attribute
} }
} }
@ -106,3 +113,12 @@ func replaceEscaping(target string, rollback bool) (s string) {
return return
} }
func hasString(lst []string, v string) bool {
for i := range lst {
if lst[i] == v {
return true
}
}
return false
}

View file

@ -25,7 +25,6 @@ func TestParseV2Attributes(t *testing.T) {
bad := append(good, "StorageType:SSD/Cell:QLC") bad := append(good, "StorageType:SSD/Cell:QLC")
_, err = attributes.ParseV2Attributes(bad, nil) _, err = attributes.ParseV2Attributes(bad, nil)
require.Error(t, err) require.Error(t, err)
}) })
t.Run("malformed", func(t *testing.T) { t.Run("malformed", func(t *testing.T) {
@ -69,4 +68,30 @@ func TestParseV2Attributes(t *testing.T) {
require.Equal(t, attrs[1].Key(), `Ke/y2`) require.Equal(t, attrs[1].Key(), `Ke/y2`)
require.Equal(t, attrs[1].Value(), `Va:lue`) require.Equal(t, attrs[1].Value(), `Va:lue`)
}) })
t.Run("same attributes", func(t *testing.T) {
from := []string{"/a:b", "/a:b"}
attrs, err := attributes.ParseV2Attributes(from, nil)
require.NoError(t, err)
require.Len(t, attrs, 1)
})
t.Run("multiple parents", func(t *testing.T) {
from := []string{
"/parent1:x/child:x",
"/parent2:x/child:x",
"/parent2:x/child:x/subchild:x",
}
attrs, err := attributes.ParseV2Attributes(from, nil)
require.NoError(t, err)
var flag bool
for _, attr := range attrs {
if attr.Key() == "child" {
flag = true
require.Equal(t, attr.ParentKeys(), []string{"parent1", "parent2"})
}
}
require.True(t, flag)
})
} }