You can trim most of it out. Instead of the 'insert' func, just m.Store() 
the new value.

But that isn't Copy-On-Write.  This is simply replacing the value in a 
variable with another value.  Anybody who read out the old value, still has 
their copy of the old value, probably stored in some variable of their 
own.  So really this is copy-on-read, not copy-on-write.

In any case, string and int64 are both immutable types, so you don't have 
to worry whether it's a copy or not.

Note that gotip has extra types like atomic.Int64, to make it easier to 
work with such values (and safer, because there's no way to access them 
accidentally without going through the synchronization interface). 
See: https://pkg.go.dev/sync/atomic@master

On Thursday, 9 June 2022 at 17:41:18 UTC+1 ag9920 wrote:

> Copy-On-Write is a classic way to deal with concurrency problems in the 
> "frequently read, but infrequently updated" scenario.
>
> I noticed an interesting discussion from a previous conversation: 
> https://groups.google.com/g/golang-nuts/c/zyQnord8hyc. The author of 
> weed-fs tried to implement Copy-On-Write by simply assigning a new value to 
> a string variable in a struct. Like this: `vs.masterNode = master`.
>
> So here comes the question, what's the recommend way of implmentating COW?
>
> The atomic package provides an example: 
> https://pkg.go.dev/sync/atomic#example-Value-ReadMostly
>
> import (
>   "sync"
>   "sync/atomic"
> )
>
> func main() {
>   type Map map[string]string
>   var m atomic.Value
>   m.Store(make(Map))
>   var mu sync.Mutex // used only by writers
>   // read function can be used to read the data without further 
> synchronization
>   read := func(key string) (val string) {
>     m1 := m.Load().(Map)
>     return m1[key]
>   }
>   // insert function can be used to update the data without further 
> synchronization
>   insert := func(key, val string) {
>     mu.Lock() // synchronize with other potential writers
>     defer mu.Unlock()
>     m1 := m.Load().(Map) // load current value of the data structure
>     m2 := make(Map)      // create a new value
>     for k, v := range m1 {
>       m2[k] = v // copy all data from the current object to the new one
>     }
>     m2[key] = val // do the update that we need
>     m.Store(m2)   // atomically replace the current object with the new one
>     // At this point all new readers start working with the new version.
>     // The old version will be garbage collected once the existing readers
>     // (if any) are done with it.
>   }
>   _, _ = read, insert
> }
>
>
> Acutally, most of the usecase I saw use map as the underlying data 
> structure for demonstration.
>
> What's the correct way to implement COW on a string variable, or maybe 
> other primitive type like int64 ? Should I just replace the `Map` type, and 
> keep everything else the same in the above official example ?
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/2cf6d4bd-ad5f-4dff-9e2a-21585b98aca4n%40googlegroups.com.

Reply via email to