There was a possibility to panic due to such behavior:
attempted to update last-writer in lockfile without the write lock
Fixes: https://github.com/containers/storage/issues/1324
Signed-off-by: Mikhail Khachayants <tyler92@inbox.ru>
When removing layers, try to remove layers before removing their
parents, as the lower-level driver may enforce the dependency beyond
what the higher-level logic does or knows.
Do this by sorting by creation time as an attempt at flattening the
layer tree into an ordered list. It won't be correct if a parent layer
needed to be recreated, but it's more likely to be correct otherwise.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
There was a race condition if a goroutine accessed to layerStore public
methods under RO lock and at the same time ReloadIfChanged was called.
In real life, it can occurr when there are two concurrent PlayKube
requests in Podman.
Signed-off-by: Mikhail Khachayants <tyler92@inbox.ru>
We now use the golang error wrapping format specifier `%w` instead of the
deprecated github.com/pkg/errors package.
Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
... so that we don't repeat it all over the place.
Introduce a pretty ugly cleanupFailureContext variable
for that purpose; still, it's better than copy&pasting everything.
This will be even more useful soon.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
We will need want to refer to "layer" in a defer
block, in order to delete that layer. That doesn't work
with "layer" being a named return value, because a
(return nil, -1, ...) sets "layer" to nil.
So, turn "layer" into a local variable, and use an unnamed
return value. And beause all return values must be named,
or unnamed, consistently, turn "size" and "err" also into
local variables.
Then decrease the scope of the "size" and "err" local variables
to simplify understanding the code a bit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
For now, this only causes two redundant saves for
non-tarball layers, which is not useful; but it will allow
us to build infrastructure for saving the incomplete record
much earlier.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
err must be nil at that point.
This also un-indents the success case, so that
it proceeds as a straight-line code.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
When we're creating a layer using another layer as a template, add the
new layer's uncompressed and compressed digest to the maps we use to
index layers using those digests.
When we forgot to do that, searching for a layer by either would still
turn up the original template, so this didn't really break anything.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
We mistakenly mixed up the uncompressed and compressed digests when
populating the by-uncompressed-digest map.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
When we create a copy of an image's top layer that's intended to be
identical to the top layer, except for having some set of ID mappings
already applied to it, copy over the template layer's compressed and
uncompressed digest and size information, compression information,
tar-split data, and lists of used UIDs and GIDs, if we have them.
The lack of sizing information was forcing ImageSize() to regenerate the
diffs to determine the size of the mapped layers, which shouldn't have
been necessary.
Teach the overlay DiffGetter to look for files in the diff directories
of lower layers if we can't find them in the current layer, so that
tar-split can retrieve content that we didn't have to pull up.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
Adds AddNames and RemoveNames so operations which are invoked in parallel
manner can use it without destroying names from storage.
For instance
We are deleting names which were already written in store.
This creates faulty behavior when builds are invoked in parallel manner, as
this removes names for other builds.
To fix this behavior we must append to already written names and
override if needed. But this should be optional and not break public API
Following patch will be used by parallel operations at podman or buildah end, directly or indirectly.
Signed-off-by: Aditya R <arajan@redhat.com>
Account for the "diff != nil" path; try to remove even
the metadata of a layer on a failure saving.
Not that there's _much_ hope to be able to save
the version without the new layer when we weren't able
to save the version with the new layer.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Currently, if the attempts to recover from a failure
themselves fail, we don't record that at all.
That makes diagnosing the situation, or hypothetically
detecting that the cleanup could never work, much
harder.
So, log the errors.
Alternatively, we could include those failures as extra
text in the returned error; that's less likely to be lost
(e.g. a Go caller would have the extra text available, without
setting up extra infrastructure to capture logs), but possibly
harder to follow.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Don't ReadAll() from a Reader to create a buffer and then create another
Reader to read from that buffer.
Don't close a file and a decompressor that we're using to read the
file's contents when we we may still need to read from them after the
current function returns.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This allows callers of Store.PutLayer to provide the values if
they have already computed them, so that ApplyDiff does not need
to compute them again.
This could quite significantly reduce CPU usage.
The code is a bit clumsy in the use of compressedWriter; it
might make sense to implement a ReadCounter counterpart to the
existing WriteCounter.
(Note that it remains the case that during pulls, both c/image/storage
and ApplyDiff decompress the stream; c/image/storage stores the
compressed, not the decompressed, version in a temporary file.
Nothing changes about that here - it's not obvious that changing it
is worth it, and anyway it's a different concept for a different
PR/discussion.)
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Have it count the input to idLogger instead of uncompressedDigester;
they should get exactly the same data, but we are going to make
uncompressedDigester optional.
Also make the uncompressedDigester use a separate line so that we
can later change it more easily.
Should not change (observable) behavior.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
It is a tiny bit expensive, but most importantly
this moves the uses of {un,}compressedDigester so that
we can later make them optional.
Should not change behavior.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Have one section deal with detecting compression and re-assembling
the original stream, and another with computing the length and digest
of the original stream.
Should not change behavior.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
When we're applying a diff, we compress the headers and stash them
elsewhere so that we can use them to correctly reconstruct the layer if
we need to extract its contents later.
By default, the compression uses a 1MB block, and up to GOMAXPROCS
threads, which results in allocating GOMAXPROCS megabytes of memory up
front. That can be much more than we need, especially if the system has
many, many cores. Drop it down to 1 megabyte.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This helps long running processes like CRI-O to determine changes to the
local storage, while handling corrupted images automatically.
The corresponding fix in Podman [0] handles corrupt layers by reloading
the image. This does not work for CRI-O, because it will not reload the
storage on subsequent calls of pullImage if no storage modification has
been done.
[0]: b4bd886fcc
Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
Currently, layers aquired from additional layer store cannot be exported
(e.g. `podman save`, `podman push`).
This is because the current additional layer store exposes only *extracted view*
of layers. Tar is not reproducible so the runtime cannot reproduce the tar
archive that has the same diff ID as the original.
This commit solves this issue by introducing a new API "`blob`" to the
additional layer store. This file exposes the raw contents of that layer. When
*(c/storage).layerStore.Diff is called, it acquires the diff contents from this
`blob` file which the same digest as the original layer.
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
similarly to containers and images, add support for storing big data
also for layers, so that it is possible to store arbitrary data when
it is not feasible to embed it in the layers JSON metadata file.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>