Commit Graph

84 Commits

Author SHA1 Message Date
Nalin Dahyabhai 0f2bccfa56 Complete "pulling up" of images in updateNames()
When updateNames() copies an image's record from a read-only store into
the read-write store, copy the accompanying data as well.

Add fields for setting data items at creation-time to LayerOptions,
ImageOptions, and ContainerOptions to make this easier for us and our
consumers.

Replace the store-specific Create() (and the one CreateWithFlags() and
Put()) with private create() and put() methods, since they're not
intended for consumption outside of this package, and add Flags to the
options structures we pass into those methods.  In create() methods,
make copies of those passed-in options structures before modifying any
of their contents.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-03-31 10:36:30 -04:00
Nalin Dahyabhai 6d91bc12f3 cmd: add a CLI wrapper for GarbageCollect
Add "gc" as an action for the CLI wrapper, for running the
GarbageCollect() method.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-01-26 16:09:00 -05:00
Nalin Dahyabhai c9b3bdc284 imageStore: add a GarbageCollect() method
Add a GarbageCollect() method to image stores, and call it from the main
Store.GarbageCollect().

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-01-26 15:58:46 -05:00
Miloslav Trmač 8ce7409de3 Optimize the "no changes" case of imageStore.startReading further
In that case, we can just get read locks, confirm that nothing has changed,
and continue; no need for any serialization on exclusively holding
loadMut / inProcessLock.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:28 +01:00
Miloslav Trmač 3b0c425f27 Rework in-process concurrency control of imageStore
Instead of basing this on exclusivity loading via loadMut (which is AFAICS correct),
use a very traditional read-write lock to protect the fields of imageStore.
This is primarily so that all three stores use the same design.

Also explicitly document how concurrent access to fields of imageStore
is managed.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-03 23:47:14 +01:00
Miloslav Trmač 3bb4c850ed Annotate imageStore methods with the required lock access
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-03 23:47:12 +01:00
Miloslav Trmač 55d11a0389 Make change tracking error-resilient
Only update recorded LastWrite values _after_ we succesfully reload
container/image/layer stores; so, if the reload fails, the functions
will keep failing instead of using obsolete (and possibly partially loaded
and completely invalid) data.

Also, further improve mount change tracking, so that if layerStore.load()
loads it, we don't reload it afterwards.

This does not change the store.graphLock users; they will need to be cleaned up
more comprehensively, and separately, in the future.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač b2d3379ed4 Deprecate *LockFile.Modified and *LockFile.Touch
They are a shared state across all users of the *LockFile in the process,
and therefore incorrect to use for any single consumer for change tracking.

Direct users to user the new GetLastWrite, ModifiedSince, and RecordWrite,
instead, and convert all c/storage users.

In addition to just being correct, the new API is also more efficient:
- We now initialize stores with GetLastWrite before loading state;
  so, we don't trigger an immediate reload on the _second_ use of a store,
  due to the problematic semantics of .Modified().
- Unlike Modified() and Touch(), the new APi can be safely used without
  locking *LockFile.stateMutex, for a tiny speedup.

The conversion is, for now, trivial, just immediately updating the lastWrite
value after the ModifiedSince call.  That will get better.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač b74fdf4d23 Convert all c/storage users of Locker to *lockfile.LockFile
This will allow us to benefit from new features.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač d1e7432233 Remove incorrect (*imageStore) type checks
They don't, as the code assumes, test whether the store
is writable; they return true for read-only stores as well.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-12 23:40:16 +01:00
Miloslav Trmač 49ca15643e Remove unnecessary writes to BigDataDigests and BigDataSizes
This makes the functions pure readers that can be used concurrently
with other readers.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-12 23:40:16 +01:00
Miloslav Trmač 0e81c378bf Clean up duplicate image names in readers instead of failing
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 859d1791b8 In load methods, track the inconsistency we want to fix
... as an error value instead of just a boolean.  That
will allow extending the logic to more kinds of inconsistencies,
and consolidates the specifics of the inconsistency knowledge
into a single place.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 765414fbdb Use the simplest possible error handling flow in reloadIfChanged
... instead of combining control flow branches; we will change
behavior on some of them.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 7c5820ae1d Don't silently ignore failures to decode metadata JSON
Also tighten the scope of some error variables a bit.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-25 20:50:23 +02:00
Miloslav Trmač cf6f6f7629 Modify imageStore not to rely on lockfile.Locked()
Instead, have the callers of ReloadIfChanged provide the
locking state.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-21 21:10:33 +02:00
Miloslav Trmač 5c6186fe81 Fix {layerStore,imageStore}.startWriting()
This is a bad bug: we wouldn't reload state from disk
at all in writers.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-19 06:35:44 +02:00
Miloslav Trmač 8db2532e49 Move imageStore.ReloadIfChanged
... to be closer to the lock / load set of methods.

Only moves unchanged code, should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 360bfae52a Remove Lock/Unlock methods from imageStore
They are now only used in the constructors, so use a variant
of startReading/startWriting instead.  This code path is not
performance-critical, so let's share as much code as possible
to ensure consistency in locking.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 8af42de786 Remove Save() from rwImageStore API
It is done implicitly by all writers already.

Also fix the documentation not to point at an explicit Touch(),
which is not actually necessary.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 097e954764 Remove Load() and ReloadIfChanged() from roImageStore API
Callers should just use startReading/startWriting.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 77ab6e4204 Remove unused lockfile forwarders from roImageStore API
The only callers are internal, have them access r.lockfile directly.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 19659d9a01 Remove a completely unused method from roImageStore
Exposing the internals of the lock is not necessary, and exposes
too many implementation details.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač d312f1dffa Move the writing lock methods from roImageStore to rwImageStore
... for a bit of extra safety. That requires us to be a bit
more explicit in one of the users.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 2f68ba24c1 Replace imageStore.{Lock,Unlock} with {startWriting,stopWriting}
This integrates ReloadIfChanged, and makes it clearer that the responsibility
for maintaining locking details is with the imageStore; we can change it
in a single place.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač a047bc18e4 Replace imageStore.{RLock,Unlock} with {startReading,stopReading}
This integrates ReloadIfChanged, and makes it clearer that the responsibility
for maintaining locking details is with the imageStore; we can change it
in a single place.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 9844aa39cb Copy methods from included interfaces directly into *ImageStore
... so that we can modify/replace them.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač 703cbe965b Simplify the name update call stack
Instead of going
	3 store methods
	store.updateNames+enum
	3 sub-store methods
	subStore.updateNames+enum
	applyNameOperation+enum,
simplify to
	3 store methods
	store.updateNames+enum
	subStore.updateNames+enum
	applyNameOperation+enum,

Should not change behavior. Looking purely at updateNameOperation,
invalid values would now be detected after doing more work,
but there is no way for an external caller to trigger use of
an invalid value anyway.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-14 17:23:08 +02:00
Miloslav Trmač b157e14dd0 Remove completely unused *Store.Lookup() methods
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:29:02 +02:00
Miloslav Trmač 821084ee68 Make all the various *Store interfaces, apart from storage.Store, private
There is no public way to obtain implementations of these interfaces; so
replace the public interfaces with private ones, to make it clear that we
_can_ modify them.

For formal API compatibility, preserve the old interface definitions
as copies.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:25:19 +02:00
Miloslav Trmač 082a8161ed Remove lockfile.Locker.RecursiveLock
It is not valid as currently implemented, and there is no known user.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-07 19:45:14 +02:00
Miloslav Trmač a02dbdbfa1 Only touch lock files after successful JSON writes
AtomicWriteFile truly is atomic, it only changes the file
on success. So there's no point notifying other processes about
a changed file if we failed, they are going to see the same JSON data.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:52 +02:00
Miloslav Trmač d1de06c839 Be explicit about how we ignore errors using trucindex.TruncIndex
This does not change behavior, it just makes it clearer
what is going on.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:52 +02:00
Daniel J Walsh c9c7d28334
Fix accessing containers and image locks
Match containers and image lock to the new layer lock method.
in https://github.com/containers/storage/pull/1351

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2022-09-28 05:45:56 -04:00
Miloslav Trmač 4b28197720 Use os.ReadFile instead of ioutil.ReadFile
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-09-12 16:30:43 +02:00
Nalin Dahyabhai 47c94cab85 Image.recomputeDigests(): don't call digest.Validate() twice
Don't call Validate() on a digest a second time if it returns an error
the first time, when it's easy to just remember the error it returned
the first time.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2022-07-25 10:56:24 -04:00
Daniel J Walsh 3f8c0dc0de
Wrap errors properly with fmt.Errorf
Also returned errors should not begine with a capatalized errors.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2022-07-12 13:26:10 -04:00
Sascha Grunert 3455d12729
Switch to golang native error wrapping
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>
2022-07-07 13:22:46 +02:00
Aditya R 4c37491c64
store: add independent AddNames and RemoveNames for images,layers,containers
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>
2022-03-01 01:33:35 +05:30
Miloslav Trmač 281a1c57b2 Fix an ignored error return value.
The "if err == nil" is always true, because
there are no prior assignments to err; but it
creates a new scope, making the "err = r.Save()"
call write to an ignored variable.

Remove the unnecessary condition to avoid that.

(Note that the code still continues on after a failure
to save, i.e. it returns a reference to a created in-memory-only
container along with the error value.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-22 19:39:11 +01:00
Giuseppe Scrivano abb54202ce
store: ReloadIfChanged propagates errors from Modified()
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2021-05-27 14:55:42 +02:00
Giuseppe Scrivano 0f5231b7bb
store: new method ROFileBasedStore.ReloadIfChanged()
add a new method to reload the store information from the hard disk if
has changed.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2021-05-13 09:05:42 +02:00
Nalin Dahyabhai 5ef1e9d68b Use json-iterator instead of encoding/json
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-05-06 12:24:24 -04:00
Giuseppe Scrivano a8da4fdb58
store: support mapped layers deletion
currently it is not possible to delete a mapped layer as it is always
referenced by the image.

Change it allow deleting the mapping if it is not used by any
container or other layers.

It will be useful in CRI-O as a lot of thrown away containers will be
created and the mapped images would keep growing without a way of
cleaning them up.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2020-08-05 13:33:43 +02:00
Sascha Grunert fd72b45a3f
Enable golint linter and fix lints
Signed-off-by: Sascha Grunert <sgrunert@suse.com>
2020-01-28 15:59:15 +01:00
Sascha Grunert ecb04cf484
Add names-history support
This commit adds a new `NamesHistory` field to the `images.json`, which
is basically a deduped list of names the image had in the past. The
first entry of the list is the latest history entry.

The main use case for this feature is to tell the end-user which
names/tags an image had in the past if it does not contain any `names`
any more.

Detailed use case:
1. Pulling `image:v1` into the local registry: `names: [ "image:v1" ]`
2. Pushing a new image as `image:v1` into the remote registry
3. Pulling `image:v1` again into the local registry:
    - first image: `names: [ "image:v1" ]`
    - previous v1 image: `names: [], names-history: [ "image:v1" ]`
4. An consumer of the storage API can now process the image name and
   still display `image` as REPOSITORY, like:
   * Before:
   ```
   > podman images
   REPOSITORY      TAG      IMAGE ID       CREATED          SIZE
   image           v1       25b62d1b654a   13 seconds ago   2.07 kB
   <none>          <none>   b134eff7b955   17 seconds ago   2.07 kB
   ```
   * After:
   ```
   > podman images
   REPOSITORY      TAG      IMAGE ID       CREATED          SIZE
   image           v1       25b62d1b654a   13 seconds ago   2.07 kB
   image           <none>   b134eff7b955   17 seconds ago   2.07 kB
   ```
5. Since the `NamesHistory` is a slice we would be able to tell the
   end-user which names an image ID had before.

The change should be backwards compatible with previous versions of
containers/storage.

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
2019-11-11 10:21:14 +01:00
Valentin Rothberg a427596d18 wrap ID or digest to ErrImageUnkown errors
Wrap the ID or the digest to ErrImageUnknown errors to avoid ambiguity
which image is unknown.  Consumers of the storage library may have
multiple subsequent calls to the storage API where it can be unclear
which image is unknown.  Wrapping the ID and digest attempts to avoid
this ambiguity.

Related-to:    github.com/containers/libpod/issues/2979
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2019-09-11 10:03:08 +02:00
Nalin Dahyabhai 47335895e5 locking: take read locks on read-only stores
Use RLock() to lock stores that we know are read-only, and panic in
Lock() if we know that we're not a read-write lock.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2019-07-02 11:14:03 -04:00
Nalin Dahyabhai d60a53b30b
Merge pull request #347 from vrothberg/recursive-locks
lockfile: add RecursiveLock() API
2019-05-31 10:10:21 -04:00
Valentin Rothberg 237602b4b8 lockfile: add RecursiveLock() API
Add a RecursiveLock() API to allow for recursive acquisitions of a
writer lock within the same process space.  This is yet another
requirement for the copy-detection mechanism in containers/image where
multiple goroutines can be pulling the same blob.  Having a recursive
lock avoids a complex synchronization mechanism as the commit order is
determinted by the corresponding index in the image.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2019-05-22 17:05:38 +02:00