puzpuzpuz / xsync

Concurrent data structures for Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[xsync.MapOf] Atomically delete a value based on value's state?

alberto-miranda opened this issue Β· comments

Hi! We are using xsync.MapOf for a couple of projects (great package btw πŸ˜‰ ) and we recently have a new use case where we would need to delete a value atomically if and only if such value meets certain conditions. Basically something like this:

func main() {
	ms := xsync.NewMapOf[int, []string]()

	id := 42

	// Delete the value atomically if and only if someCondition and someOtherCondition are true
	v, deleted := ms.DeleteIf(id, func(value []string) bool {
		if someCondition(value) && someOtherCondition(value) {
			return true
		}

		return false
	})

	// If the value was deleted, we can use it safely since it's not in the map anymore
	if deleted {
		fmt.Printf("v: %v\n", v)
	}
}

Is there a way to do this with MapOf? If there isn't and the implementation is not very complex, would you accept a contribution for this?

Hello,

You can use Compute for this purpose: if it's delete return value is true, the key will be deleted. See the Delete an existing value part of the doc example.

Thanks for the prompt response. Is a strict ordering guaranteed between competing calls to Compute() and Load() in different goroutines? We wrote a small test to validate our implementation, where a goroutine tries to Load() a key concurrently with a deletion, and it looks like Load() is able to find the value while the valueFn passed to Compute is being executed. We assumed that once valueFn started its execution, other goroutines would be blocked until it completed, but maybe we were wrong about this?

Writes, e.g. Compute or Store or Delete, never block reads, e.g. Load or Range. That's the reason why MapOf reads scale in terms of core/goroutine count. In your case, you could try using Compute for both reads and writes - readers may simply read the key and do something about it while writers will be deleting it based on a condition. Just make sure to do this in the function provided to the Compute call - otherwise, as soon as your code leaves the function, a concurrent reader/writer may do something with the key.

Great, thanks, we will attempt what you propose. It will not be as performant as it could, but it will be consistent which is what we need right now.