[#102] container: Make Put and Delete stable for simultaneous invocations in one block

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2021-06-30 16:59:50 +03:00 committed by Alex Vanin
parent c368eac796
commit 98c5fd25c3

View file

@ -44,7 +44,6 @@ type (
const ( const (
version = 1 version = 1
ownersKey = "ownersList"
neofsIDContractKey = "identityScriptHash" neofsIDContractKey = "identityScriptHash"
balanceContractKey = "balanceScriptHash" balanceContractKey = "balanceScriptHash"
@ -118,9 +117,7 @@ func Put(container []byte, signature interop.Signature, publicKey interop.Public
ctx := storage.GetContext() ctx := storage.GetContext()
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
offset := int(container[1]) ownerID := ownerFromBinaryContainer(container)
offset = 2 + offset + 4 // version prefix + version size + owner prefix
ownerID := container[offset : offset+25] // offset + size of owner
containerID := crypto.Sha256(container) containerID := crypto.Sha256(container)
neofsIDContractAddr := storage.Get(ctx, neofsIDContractKey).(interop.Hash160) neofsIDContractAddr := storage.Get(ctx, neofsIDContractKey).(interop.Hash160)
cnr := Container{ cnr := Container{
@ -258,19 +255,10 @@ func List(owner []byte) [][]byte {
var list [][]byte var list [][]byte
owners := common.GetList(ctx, ownersKey) it := storage.Find(ctx, owner, storage.ValuesOnly)
for i := 0; i < len(owners); i++ { for iterator.Next(it) {
ownerID := owners[i] id := iterator.Value(it).([]byte)
if len(owner) != 0 && !common.BytesEqual(owner, ownerID) { list = append(list, id)
continue
}
containers := common.GetList(ctx, ownerID)
for j := 0; j < len(containers); j++ {
container := containers[j]
list = append(list, container)
}
} }
return list return list
@ -511,62 +499,19 @@ func Version() int {
} }
func addContainer(ctx storage.Context, id, owner []byte, container Container) { func addContainer(ctx storage.Context, id, owner []byte, container Container) {
addOrAppend(ctx, ownersKey, owner) containerListKey := append(owner, id...)
addOrAppend(ctx, owner, id) storage.Put(ctx, containerListKey, id)
common.SetSerialized(ctx, id, container) common.SetSerialized(ctx, id, container)
} }
func removeContainer(ctx storage.Context, id []byte, owner []byte) { func removeContainer(ctx storage.Context, id []byte, owner []byte) {
n := remove(ctx, owner, id) containerListKey := append(owner, id...)
storage.Delete(ctx, containerListKey)
// if it was last container, remove owner from the list of owners
if n == 0 {
_ = remove(ctx, ownersKey, owner)
}
storage.Delete(ctx, id) storage.Delete(ctx, id)
} }
func addOrAppend(ctx storage.Context, key interface{}, value []byte) {
list := common.GetList(ctx, key)
for i := 0; i < len(list); i++ {
if common.BytesEqual(list[i], value) {
return
}
}
if len(list) == 0 {
list = [][]byte{value}
} else {
list = append(list, value)
}
common.SetSerialized(ctx, key, list)
}
// remove returns amount of left elements in the list
func remove(ctx storage.Context, key interface{}, value []byte) int {
var (
list = common.GetList(ctx, key)
newList = [][]byte{}
)
for i := 0; i < len(list); i++ {
if !common.BytesEqual(list[i], value) {
newList = append(newList, list[i])
}
}
ln := len(newList)
if ln == 0 {
storage.Delete(ctx, key)
} else {
common.SetSerialized(ctx, key, newList)
}
return ln
}
func getAllContainers(ctx storage.Context) [][]byte { func getAllContainers(ctx storage.Context) [][]byte {
var list [][]byte var list [][]byte
@ -600,21 +545,15 @@ func getContainer(ctx storage.Context, cid []byte) Container {
return Container{value: []byte{}, sig: interop.Signature{}, pub: interop.PublicKey{}, token: []byte{}} return Container{value: []byte{}, sig: interop.Signature{}, pub: interop.PublicKey{}, token: []byte{}}
} }
func getOwnerByID(ctx storage.Context, id []byte) []byte { func getOwnerByID(ctx storage.Context, cid []byte) []byte {
owners := common.GetList(ctx, ownersKey) container := getContainer(ctx, cid)
for i := 0; i < len(owners); i++ { return ownerFromBinaryContainer(container.value)
ownerID := owners[i]
containers := common.GetList(ctx, ownerID)
for j := 0; j < len(containers); j++ {
container := containers[j]
if common.BytesEqual(container, id) {
return ownerID
}
}
} }
return nil func ownerFromBinaryContainer(container []byte) []byte {
offset := int(container[1])
offset = 2 + offset + 4 // version prefix + version size + owner prefix
return container[offset : offset+25] // offset + size of owner
} }
func estimationKey(epoch int, cid []byte) []byte { func estimationKey(epoch int, cid []byte) []byte {