-
Notifications
You must be signed in to change notification settings - Fork 251
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
Allow GetStore()
in read-only mode
#420
Comments
That should work - at least for containers/storage. In this specific example, when listing images, the image-storage is used read-only (see https://github.com/containers/storage/blob/master/store.go#L2810). The locks are then acquired read-only to allow for multi-reader, single-writer scenarios. Did you strace which lock we're blocked on in the upper example? |
I can reproduce it locally as well. Maybe, we miss a reader lock in one code path in that scenario :( Great catch btw, @saschagrunert ! |
Yeah, in the above scenario it blocks there in containers/storage: Line 485 in 69bcd96
Which traces up to libpod configureStore() :https://github.com/containers/libpod/blob/master/libpod/runtime.go#L1394 The internal Lines 670 to 673 in 69bcd96
This also effects every consumer of the |
If we did a
The impact of this specific lock should be minimal. It's a short critical section needed to initialize the storage on disk. I don't think we can get rid of them. |
@nalind PTAL |
I'll take that back. The |
I am under the impression that the pushing process monopolizes the lock where @saschagrunert pointed to (i.e., the Changing it to an RLock() makes it run in parallel. @nalind, is there any way we can avoid the writer lock here? |
What do you mean with short lived? If I push then it blocks during the whole image push (which can be pretty long). During pull, it only blocks on "Storing signatures", which can also take longer time if the target image is large. |
Looking at Line 485 in 69bcd96
newLayerStore . That's why short-lived; the critical section is small.
I don't understand how this lock could be held entirely as it's being released at return of this function (see above) and acquired multiple times. The lock monopolization, however, would make it seem like it's being held for the entire push.
Right. The blobs are first downloaded in |
During a push of And I get 75 when listing images 👀 |
I took more time of investigating how the storage locking behaves and could not find any wrong behavior. For example when pushing an image and parallel trying to list the images, then the push read-locks the storage for every layer, which is correct. The main issue I can see is that we need write-lock access to the storage on If we hack a bit around and replace both locks with an diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index d746ba06..46b0f099 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -482,7 +482,7 @@ func newLayerStore(rundir string, layerdir string, driver drivers.Driver, uidMap
if err != nil {
return nil, err
}
- lockfile.Lock()
+ lockfile.RLock()
defer lockfile.Unlock()
mountsLockfile, err := GetLockfile(filepath.Join(rundir, "mountpoints.lock"))
if err != nil {
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 74275482..66290b53 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -3130,7 +3130,7 @@ func (s *store) Shutdown(force bool) ([]string, error) {
s.graphLock.Lock()
defer s.graphLock.Unlock()
- rlstore.Lock()
+ rlstore.RLock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
if err = rlstore.Load(); err != nil { This is for sure not safe, because we're now mixing two use cases. What we could do is to provide a completely read-only store via an API, but then the consumer has to specify which type (read, readWrite) of store is needed... This means that we either extend the API, or we do not write the store on |
That aligns with my findings in #420 (comment).
I have hopes that we can find a work-around to avoid acquiring the lock(s) as a writer but we need @nalind's pair of eyes to be sure. |
@nalind @vrothberg @saschagrunert Anyone have time to pursue this? |
Yes, but we're still waiting for feedback from @nalind :) |
I'm fine with that if it does the job without dramatically increasing the complexity of the code. |
Alright, I will put this on my list of TODOs but may start after kubecon |
@saschagrunert Any movement on this? Or still waiting for #473 to get merged? |
Yes I think #473 is a per-requirement for this more in-depth enhancement :) Once we can merge this I can continue my work here. |
@saschagrunert What should we do with this one now? |
Closing this since I don't see a valid path forward. |
The idea is to retrieve an instance of the store in read-only mode, which for sure does not allow any modifications at all.
This would reduce the locking on the store where it is not necessary, for example when listing images.
Right now, it is not possible to execute two read-only operations like this:
and in a second shell:
Target of the implementation would be that the consumers of the API can decide if they want a read-only store instance or not.
The text was updated successfully, but these errors were encountered: