qemu/util/transactions.c
Hanna Reitz 079bff693b transactions: Invoke clean() after everything else
Invoke the transaction drivers' .clean() methods only after all
.commit() or .abort() handlers are done.

This makes it easier to have nested transactions where the top-level
transactions pass objects to lower transactions that the latter can
still use throughout their commit/abort phases, while the top-level
transaction keeps a reference that is released in its .clean() method.

(Before this commit, that is also possible, but the top-level
transaction would need to take care to invoke tran_add() before the
lower-level transaction does.  This commit makes the ordering
irrelevant, which is just a bit nicer.)

Signed-off-by: Hanna Reitz <hreitz@redhat.com>
Message-Id: <20211111120829.81329-8-hreitz@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20211115145409.176785-8-kwolf@redhat.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
2021-11-16 09:43:44 +01:00

100 lines
2.3 KiB
C

/*
* Simple transactions API
*
* Copyright (c) 2021 Virtuozzo International GmbH.
*
* Author:
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/transactions.h"
#include "qemu/queue.h"
typedef struct TransactionAction {
TransactionActionDrv *drv;
void *opaque;
QSLIST_ENTRY(TransactionAction) entry;
} TransactionAction;
struct Transaction {
QSLIST_HEAD(, TransactionAction) actions;
};
Transaction *tran_new(void)
{
Transaction *tran = g_new(Transaction, 1);
QSLIST_INIT(&tran->actions);
return tran;
}
void tran_add(Transaction *tran, TransactionActionDrv *drv, void *opaque)
{
TransactionAction *act;
act = g_new(TransactionAction, 1);
*act = (TransactionAction) {
.drv = drv,
.opaque = opaque
};
QSLIST_INSERT_HEAD(&tran->actions, act, entry);
}
void tran_abort(Transaction *tran)
{
TransactionAction *act, *next;
QSLIST_FOREACH(act, &tran->actions, entry) {
if (act->drv->abort) {
act->drv->abort(act->opaque);
}
}
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
if (act->drv->clean) {
act->drv->clean(act->opaque);
}
g_free(act);
}
g_free(tran);
}
void tran_commit(Transaction *tran)
{
TransactionAction *act, *next;
QSLIST_FOREACH(act, &tran->actions, entry) {
if (act->drv->commit) {
act->drv->commit(act->opaque);
}
}
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
if (act->drv->clean) {
act->drv->clean(act->opaque);
}
g_free(act);
}
g_free(tran);
}