-
Notifications
You must be signed in to change notification settings - Fork 475
fix LibVirtPoolSync #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix LibVirtPoolSync #159
Conversation
The code looks good, however I think we should understand why we are trying to unlock the same lock twice. Why and how is this happening? Then we can create a proper fix, this one looks like a workaround. Can you reproduce the issue? If so do you know what might be the cause of it? |
I was able to reproduce issue #121 by patching diff --git a/libvirt/pool_sync.go b/libvirt/pool_sync.go
index 8c53ac05..6a6fe9c2 100644
--- a/libvirt/pool_sync.go
+++ b/libvirt/pool_sync.go
@@ -1,6 +1,7 @@
package libvirt
import (
+ "log"
"sync"
)
@@ -29,9 +30,11 @@ func (ps LibVirtPoolSync) AcquireLock(pool string) {
lock, exists := ps.PoolLocks[pool]
if !exists {
lock = new(sync.Mutex)
+ log.Printf("[DEBUG] acquire lock (1); pool: '%s', ps: %+v, lock: %+v\n", pool, ps, lock)
ps.PoolLocks[pool] = lock
}
+ log.Printf("[DEBUG] acquire lock (2); pool: '%s', ps: %+v, lock: %+v\n", pool, ps, lock)
lock.Lock()
}
@@ -45,5 +48,6 @@ func (ps LibVirtPoolSync) ReleaseLock(pool string) {
return
}
+ log.Printf("[DEBUG] release lock; pool: '%s', ps: %+v, lock: %+v\n", pool, ps, lock)
lock.Unlock()
} (Oddly, it won't fail without the 1st The Terraform file: provider "libvirt" {
uri = "qemu:///system"
}
resource "libvirt_cloudinit" "disk" {
name = "commoninit.iso"
local_hostname = "node"
pool = "home"
}
resource "libvirt_volume" "disk" {
name = "disk_${count.index}"
size = "40960"
pool = "home"
count = 1
} (I guess it's just important to have multiple volumes) The log shows the following:
This raises the question as to why two separate mutexes for |
After searching the web, I found this: golang/go#20060. I guess we're doing it wrong. I'll fix this. |
FYI:
Perhaps we should run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the right approach to the problem. I would create a singleton instance (a global, static instance, initialized probably in a init()
function) and use it as a gatekeeper to the pools. I find the idea of keeping another map with booleans slightly hackish...
@@ -62,7 +62,11 @@ func (ci *defCloudInit) CreateAndUpload(virConn *libvirt.Connect) (string, error | |||
} | |||
defer pool.Free() | |||
|
|||
PoolSync.AcquireLock(ci.PoolName) | |||
for { | |||
if PoolSync.AcquireLock(ci.PoolName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looping until we get the lock doesn't seem a very elegant solution...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know how to avoid looping in this case. I added a time.Sleep(..)
to make it more CPU-friendly ;)
libvirt/pool_sync.go
Outdated
|
||
return pool | ||
return &pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use a more go-ish syntax:
func NewLibVirtPoolSync() *LibVirtPoolSync {
return &LibVirtPoolSync{
PoolLocks: make(map[string]*sync.Mutex),
//...
}
}
Declare methods of LibVirtPoolSync as pointers since otherwise the entire construct is ineffective. Callers of `AcquireLock` are now responsible for making sure that the mutex is locked. This will prevent the following errors: * fatal error: concurrent map writes * panic: sync: unlock of unlocked mutex This fixes #121. Signed-off-by: Thomas Hipp <[email protected]>
Change code structure, and sleep after trying (and failing) to acquire a lock. Signed-off-by: Thomas Hipp <[email protected]>
Declare methods of LibVirtPoolSync as pointers since otherwise the
entire construct is ineffective. Callers of
AcquireLock
are nowresponsible for making sure that the mutex is locked.
This will prevent the following errors:
* fatal error: concurrent map writes
* panic: sync: unlock of unlocked mutex
This fixes #121.
Signed-off-by: Thomas Hipp [email protected]