From 71d3d399d7de75a96b2911677b74ce8b59579ee9 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 4 Feb 2025 18:22:35 +0100 Subject: Introduce pkgDepCache::Transaction for transactional depcache updates --- apt-pkg/depcache.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ apt-pkg/depcache.h | 38 ++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) (limited to 'apt-pkg') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 970b4c01d..ec34d010b 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -2650,3 +2650,74 @@ unsigned long long pkgDepCache::BootSize(bool initrdOnly) return std::accumulate(sizes, sizes + MAX_ARTEFACT, off_t{0}) * BootCount * 110 / 100; } /*}}}*/ +// pkgDepCache::Transaction /*{{{*/ +struct pkgDepCache::Transaction::Private +{ + template + static T *copyArray(T *array, size_t count) + { + auto out = new T[count]; + memcpy(&out[0], &array[0], sizeof(T) * count); + return out; + } + // State information + pkgDepCache &cache; + Behavior behavior; + std::unique_ptr PkgState{copyArray(cache.PkgState, cache.GetCache().Head().PackageCount)}; + std::unique_ptr DepState{copyArray(cache.DepState, cache.GetCache().Head().DependsCount)}; + signed long long iUsrSize{cache.iUsrSize}; + unsigned long long iDownloadSize{cache.iDownloadSize}; + unsigned long iInstCount{cache.iInstCount}; + unsigned long iDelCount{cache.iDelCount}; + unsigned long iKeepCount{cache.iKeepCount}; + unsigned long iBrokenCount{cache.iBrokenCount}; + unsigned long iPolicyBrokenCount{cache.iPolicyBrokenCount}; + unsigned long iBadCount{cache.iBadCount}; + + void rollback() + { + memcpy(&cache.PkgState[0], &PkgState[0], sizeof(PkgState[0]) * cache.GetCache().Head().PackageCount); + memcpy(&cache.DepState[0], &DepState[0], sizeof(DepState[0]) * cache.GetCache().Head().DependsCount); + + cache.iUsrSize = iUsrSize; + cache.iDownloadSize = iDownloadSize; + cache.iInstCount = iInstCount; + cache.iDelCount = iDelCount; + cache.iKeepCount = iKeepCount; + cache.iBrokenCount = iBrokenCount; + cache.iPolicyBrokenCount = iPolicyBrokenCount; + cache.iBadCount = iBadCount; + } +}; + +pkgDepCache::Transaction::Transaction(pkgDepCache &cache, Behavior behavior) : d(new Private{cache, behavior}) {} + +void pkgDepCache::Transaction::temporaryRollback() +{ + d->rollback(); +} + +void pkgDepCache::Transaction::commit() +{ + d.reset(); +} + +void pkgDepCache::Transaction::rollback() +{ + if (d == nullptr) + return; + + temporaryRollback(); + d.reset(); +} + +pkgDepCache::Transaction::~Transaction() +{ + if (not d) + return; + if (d->behavior == Behavior::ROLLBACK || (d->behavior == Behavior::AUTO && d->cache.iBrokenCount > d->iBrokenCount)) + rollback(); + else + commit(); +} + /*}}}*/ diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 39d34d3e4..d2a883180 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -267,6 +267,42 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace bool InstallSuggests; }; + /** + * \brief Perform changes to the depcache atomically. + * + * The default policy for a transaction is to rollback if the number of broken packages + * increased, otherwise to commit. Call commit() or rollback() to override the default + * policy. + */ + class APT_PUBLIC Transaction final + { + struct Private; + std::unique_ptr d; + + public: + enum class Behavior + { + COMMIT, + ROLLBACK, + AUTO, + }; + + explicit Transaction(pkgDepCache &cache, Behavior behavior); + /** \brief Commit the transaction immediately */ + void commit(); + /** \brief Rollback the transaction immediately */ + void rollback(); + /** \brief Like rollback, but can be called multiple times. + * + * You can for example create a new transaction, then temporarily + * rollback to the state before the previous transaction in that + * transaction. + */ + void temporaryRollback(); + /** \brief Commit or rollback the transaction based on default policy */ + ~Transaction(); + }; + private: /** The number of open "action groups"; certain post-action * operations are suppressed if this number is > 0. @@ -274,6 +310,8 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace int group_level; friend class ActionGroup; + friend class Transaction; + public: int IncreaseActionGroupLevel(); int DecreaseActionGroupLevel(); -- cgit v1.2.3-70-g09d2