I have a hash like this:
var TransfersInFlight map[string]string = make(map[string]string)
And before I send a file I make a key for it store, send it, delete it:
timeKey := fmt.Sprintf("%v",time.Now().UnixNano())
TransfersInFlight[timeKey] = filename
total, err := sendTheFile(filename)
delete(TransfersInFlight, timeKey)
i.e. during the time it takes to send the file, there is a key in the hash with a timestamp pointing to the filename.
the func sendTheFile
always either works, or has an err but never throws a stacktrace exception and crashes the whole program so the line:
delete(TransfersInFlight, timeKey)
should be called 100% of the time. And yet, I sometimes find cases where it's like this line was never called and the file is stuck in TransfersInFlight forever. How is this possible?
Maps are not safe for concurrent access. I would do this either using a mutex to moderate map access or having a goroutine reading either a channel of "op" structs or have a "add" channel and a "delete" channel.
You're probably safe having multiple read-only accesses concurrently, but once you have writes in the mix, you really want to ensure you only have one access at a time.
If you are set on using a goroutine to manage the count, one way would be something like:
import "sync/atomic"
var TransferChan chan int32
var TransfersInFlight int32
func TransferManager() {
TransfersInFlight = 0
for delta := range TransferChan {
// You're *probably* safe just using +=, but, you know...
atomic.AddInt32(&TransfersInFlight, delta)
}
}
That way, you only need to do go TransferManager()
and then pass your increments and decrements over the TransferChan
channel.