diff --git a/storage/local/locker.go b/storage/local/locker.go index 18fbacb9dd..1628ec1275 100644 --- a/storage/local/locker.go +++ b/storage/local/locker.go @@ -22,16 +22,13 @@ import ( // fingerprintLocker allows locking individual fingerprints. To limit the number // of mutexes needed for that, only a fixed number of mutexes are // allocated. Fingerprints to be locked are assigned to those pre-allocated -// mutexes by their value. (Note that fingerprints are calculated by a hash -// function, so that an approximately equal distribution over the mutexes is -// expected, even without additional hashing of the fingerprint value.) -// Collisions are not detected. If two fingerprints get assigned to the same -// mutex, only one of them can be locked at the same time. As long as the number -// of pre-allocated mutexes is much larger than the number of goroutines -// requiring a fingerprint lock concurrently, the loss in efficiency is -// small. However, a goroutine must never lock more than one fingerprint at the -// same time. (In that case a collision would try to acquire the same mutex -// twice). +// mutexes by their value. Collisions are not detected. If two fingerprints get +// assigned to the same mutex, only one of them can be locked at the same +// time. As long as the number of pre-allocated mutexes is much larger than the +// number of goroutines requiring a fingerprint lock concurrently, the loss in +// efficiency is small. However, a goroutine must never lock more than one +// fingerprint at the same time. (In that case a collision would try to acquire +// the same mutex twice). type fingerprintLocker struct { fpMtxs []sync.Mutex numFpMtxs uint @@ -59,6 +56,13 @@ func (l *fingerprintLocker) Unlock(fp model.Fingerprint) { l.fpMtxs[hashFP(fp)%l.numFpMtxs].Unlock() } +// hashFP simply moves entropy from the most significant 48 bits of the +// fingerprint into the least significant 16 bits (by XORing) so that a simple +// MOD on the result can be used to pick a mutex while still making use of +// changes in more significant bits of the fingerprint. (The fast fingerprinting +// function we use is prone to only change a few bits for similar metrics. We +// really want to make use of every change in the fingerprint to vary mutex +// selection.) func hashFP(fp model.Fingerprint) uint { return uint(fp ^ (fp >> 32) ^ (fp >> 16)) }