summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca BRUNO <luca.bruno@coreos.com>2021-10-01 16:04:02 +0000
committerLuca BRUNO <luca.bruno@coreos.com>2021-10-05 12:23:22 +0000
commitc9875345959fb4a028a7596b643d922a952277d0 (patch)
tree9fde928d4c10a451b6d91fe5b1a91368fa50f00c /src
parent5bf4b1dabc12d6caee4f4899c9388a48bb4a72a3 (diff)
downloadostree-c9875345959fb4a028a7596b643d922a952277d0.tar.gz
repo/private: allow committing/aborting through a transaction guard
This enhances the auto-transaction logic, augmenting the scope of a transaction guard. It allows committing or aborting a transaction through its guard. It also supports tracking the completion status of a transaction guard, avoiding double commits/aborts, while retaining the auto-cleanup logic.
Diffstat (limited to 'src')
-rw-r--r--src/libostree/ostree-repo-commit.c10
-rw-r--r--src/libostree/ostree-repo-private.h65
-rw-r--r--src/libostree/ostree-repo.c112
-rw-r--r--src/libostree/ostree-sysroot-cleanup.c4
4 files changed, 156 insertions, 35 deletions
diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c
index c87e8de8..8ac963e7 100644
--- a/src/libostree/ostree-repo-commit.c
+++ b/src/libostree/ostree-repo-commit.c
@@ -1672,14 +1672,18 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
+ g_assert (self != NULL);
+
guint64 reserved_bytes = 0;
g_return_val_if_fail (self->in_transaction == FALSE, FALSE);
g_debug ("Preparing transaction in repository %p", self);
- /* Set up to abort the transaction if we return early from this function. */
- g_autoptr(_OstreeRepoAutoTransaction) txn = self;
+ /* Set up to abort the transaction if we return early from this function.
+ * This needs to be manually built here due to a circular dependency. */
+ g_autoptr(OstreeRepoAutoTransaction) txn = g_malloc(sizeof(OstreeRepoAutoTransaction));
+ txn->repo = self;
(void) txn; /* Add use to silence static analysis */
memset (&self->txn.stats, 0, sizeof (OstreeRepoTransactionStats));
@@ -1736,7 +1740,7 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
return FALSE;
/* Success: do not abort the transaction when returning. */
- txn = NULL; (void) txn;
+ txn->repo = NULL; (void) txn;
if (out_transaction_resume)
*out_transaction_resume = ret_transaction_resume;
diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h
index 67f755bd..a2666dec 100644
--- a/src/libostree/ostree-repo-private.h
+++ b/src/libostree/ostree-repo-private.h
@@ -229,36 +229,6 @@ struct OstreeRepo {
OstreeRepo *parent_repo;
};
-/* Taken from flatpak; may be made into public API later */
-typedef OstreeRepo _OstreeRepoAutoTransaction;
-static inline void
-_ostree_repo_auto_transaction_cleanup (void *p)
-{
- if (p == NULL)
- return;
- g_return_if_fail (OSTREE_IS_REPO (p));
-
- OstreeRepo *repo = p;
- g_autoptr(GError) error = NULL;
-
- if (!ostree_repo_abort_transaction (repo, NULL, &error))
- g_warning("Failed to auto-cleanup OSTree transaction: %s", error->message);
-
- g_object_unref (repo);
-}
-
-static inline _OstreeRepoAutoTransaction *
-_ostree_repo_auto_transaction_start (OstreeRepo *repo,
- GCancellable *cancellable,
- GError **error)
-{
- if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
- return NULL;
-
- return (_OstreeRepoAutoTransaction *) g_object_ref (repo);
-}
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (_OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_cleanup)
-
typedef struct {
dev_t dev;
ino_t ino;
@@ -544,4 +514,39 @@ _ostree_repo_verify_bindings (const char *collection_id,
GVariant *commit,
GError **error);
+/**
+ * OstreeRepoAutoTransaction:
+ *
+ * A transaction guard for a specific #OstreeRepo. It can be explicitly
+ * completed through abort/commit. If the guard has not been completed
+ * beforehand, on cleanup it is automatically aborted.
+ *
+ * Taken from flatpak; may be made into public API later
+ */
+typedef struct
+{
+ OstreeRepo *repo;
+} OstreeRepoAutoTransaction;
+
+OstreeRepoAutoTransaction *
+_ostree_repo_auto_transaction_start (OstreeRepo *repo,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean
+_ostree_repo_auto_transaction_abort (OstreeRepoAutoTransaction *txn,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean
+_ostree_repo_auto_transaction_commit (OstreeRepoAutoTransaction *txn,
+ OstreeRepoTransactionStats *out_stats,
+ GCancellable *cancellable,
+ GError **error);
+
+void
+_ostree_repo_auto_transaction_cleanup (void *p);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_cleanup);
+
G_END_DECLS
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 42d2b0e0..772eae26 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -711,6 +711,118 @@ ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *auto_lock)
}
}
+
+/**
+ * _ostree_repo_auto_transaction_start:
+ * @repo: an #OsreeRepo object
+ * @cancellable: Cancellable
+ * @error: a #GError
+ *
+ * Start a transaction and return a guard for it.
+ *
+ * Returns: (transfer full): an #OsreeRepoAutoTransaction guard on success,
+ * %NULL otherwise.
+ */
+OstreeRepoAutoTransaction *
+_ostree_repo_auto_transaction_start (OstreeRepo *repo,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_assert (repo != NULL);
+
+ if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
+ return NULL;
+
+ OstreeRepoAutoTransaction *txn = g_malloc(sizeof(OstreeRepoAutoTransaction));
+ txn->repo = g_object_ref (repo);
+
+ return g_steal_pointer (&txn);
+}
+
+/**
+ * _ostree_repo_auto_transaction_abort:
+ * @txn: an #OsreeRepoAutoTransaction guard
+ * @cancellable: Cancellable
+ * @error: a #GError
+ *
+ * Abort a transaction, marking the related guard as completed.
+ *
+ * Returns: %TRUE on successful commit, %FALSE otherwise.
+ */
+gboolean
+_ostree_repo_auto_transaction_abort (OstreeRepoAutoTransaction *txn,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_assert (txn != NULL);
+
+ if (txn->repo == NULL) {
+ return glnx_throw (error, "transaction already completed");
+ }
+
+ if (!ostree_repo_abort_transaction (txn->repo, cancellable, error))
+ return FALSE;
+
+ g_clear_object (&txn->repo);
+
+ return TRUE;
+}
+
+/**
+ * _ostree_repo_auto_transaction_commit:
+ * @txn: an #OsreeRepoAutoTransaction guard
+ * @cancellable: Cancellable
+ * @error: a #GError
+ *
+ * Commit a transaction, marking the related guard as completed.
+ *
+ * Returns: %TRUE on successful aborting, %FALSE otherwise.
+ */
+gboolean
+_ostree_repo_auto_transaction_commit (OstreeRepoAutoTransaction *txn,
+ OstreeRepoTransactionStats *out_stats,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_assert (txn != NULL);
+
+ if (txn->repo == NULL) {
+ return glnx_throw (error, "transaction already completed");
+ }
+
+ if (!ostree_repo_commit_transaction (txn->repo, out_stats, cancellable, error))
+ return FALSE;
+
+ g_clear_object (&txn->repo);
+
+ return TRUE;
+}
+
+/**
+ * _ostree_repo_auto_transaction_cleanup:
+ * @p: pointer to an #OsreeRepoAutoTransaction guard
+ *
+ * Destroy a transaction guard. If the transaction has not yet been completed,
+ * it gets aborted.
+ */
+void
+_ostree_repo_auto_transaction_cleanup (void *p)
+{
+ if (p == NULL)
+ return;
+
+ OstreeRepoAutoTransaction *txn = p;
+ // Auto-abort only if transaction has not already been aborted/committed.
+ if (txn->repo != NULL)
+ {
+ g_autoptr(GError) error = NULL;
+ if (!_ostree_repo_auto_transaction_abort (txn, NULL, &error)) {
+ g_warning("Failed to auto-cleanup OSTree transaction: %s", error->message);
+ g_clear_object (&txn->repo);
+ }
+ }
+}
+
static GFile *
get_remotes_d_dir (OstreeRepo *self,
GFile *sysroot);
diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c
index 91381cb0..c22a6851 100644
--- a/src/libostree/ostree-sysroot-cleanup.c
+++ b/src/libostree/ostree-sysroot-cleanup.c
@@ -445,7 +445,7 @@ generate_deployment_refs (OstreeSysroot *self,
cancellable, error))
return FALSE;
- g_autoptr(_OstreeRepoAutoTransaction) txn =
+ g_autoptr(OstreeRepoAutoTransaction) txn =
_ostree_repo_auto_transaction_start (repo, cancellable, error);
if (!txn)
return FALSE;
@@ -458,7 +458,7 @@ generate_deployment_refs (OstreeSysroot *self,
ostree_repo_transaction_set_refspec (repo, refname, ostree_deployment_get_csum (deployment));
}
- if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
+ if (!_ostree_repo_auto_transaction_commit (txn, NULL, cancellable, error))
return FALSE;
return TRUE;