544
547
def _get(cls, distribution, sourcepackagename):
545
return Store.of(distribution).find(
546
DistributionSourcePackageInDatabase,
547
DistributionSourcePackageInDatabase.sourcepackagename ==
549
DistributionSourcePackageInDatabase.distribution ==
548
return DistributionSourcePackageInDatabase.get(
549
distribution, sourcepackagename)
553
552
def _new(cls, distribution, sourcepackagename,
554
553
is_upstream_link_allowed=False):
555
dsp = DistributionSourcePackageInDatabase()
556
dsp.distribution = distribution
557
dsp.sourcepackagename = sourcepackagename
558
dsp.is_upstream_link_allowed = is_upstream_link_allowed
559
Store.of(distribution).add(dsp)
560
Store.of(distribution).flush()
554
return DistributionSourcePackageInDatabase.new(
555
distribution, sourcepackagename, is_upstream_link_allowed)
564
558
def ensure(cls, spph=None, sourcepackage=None):
591
585
cls._new(distribution, sourcepackagename, upstream_link_allowed)
588
class ThreadLocalLRUCache(LRUCache, local):
589
"""A per-thread LRU cache that can synchronize with a transaction."""
591
implements(transaction.interfaces.ISynchronizer)
593
def newTransaction(self, txn):
596
def beforeCompletion(self, txn):
599
def afterCompletion(self, txn):
600
# Clear the cache when a transaction is committed or aborted.
594
604
class DistributionSourcePackageInDatabase(Storm):
595
605
"""Temporary class to allow access to the database."""
627
637
releases = self.distribution.getCurrentSourceReleases(
628
638
[self.sourcepackagename])
629
639
return releases.get(self)
641
# This is a per-thread LRU cache of mappings from (distribution_id,
642
# sourcepackagename_id)) to dsp_id. See get() for how this cache helps to
643
# avoid database hits without causing consistency issues.
644
_cache = ThreadLocalLRUCache(1000, 700)
645
# Synchronize the mapping cache with transactions. The mapping is not
646
# especially useful after a tranaction completes because Storm invalidates
647
# its caches, and leaving the mapping cache in place causes difficult to
648
# understand test interactions.
649
transaction.manager.registerSynch(_cache)
652
def get(cls, distribution, sourcepackagename):
653
"""Get a DSP given distribution and source package name.
655
Attempts to use a cached `(distro_id, spn_id) --> dsp_id` mapping to
656
avoid hitting the database.
658
# Check for a cached mapping from (distro_id, spn_id) to dsp_id.
659
dsp_cache_key = distribution.id, sourcepackagename.id
660
dsp_id = cls._cache.get(dsp_cache_key)
661
# If not, fetch from the database.
663
return cls.getDirect(distribution, sourcepackagename)
664
# Try store.get(), allowing Storm to answer from cache if it can.
665
store = Store.of(distribution)
666
dsp = store.get(DistributionSourcePackageInDatabase, dsp_id)
667
# If it's not found, query the database; the mapping might be stale.
669
return cls.getDirect(distribution, sourcepackagename)
670
# Check that the mapping in the cache was correct.
671
if distribution.id != dsp.distribution_id:
672
return cls.getDirect(distribution, sourcepackagename)
673
if sourcepackagename.id != dsp.sourcepackagename_id:
674
return cls.getDirect(distribution, sourcepackagename)
679
def getDirect(cls, distribution, sourcepackagename):
680
"""Get a DSP given distribution and source package name.
682
Caches the `(distro_id, spn_id) --> dsp_id` mapping, but does not
683
otherwise use the cache; it always goes to the database.
685
dsp = Store.of(distribution).find(
686
DistributionSourcePackageInDatabase,
687
DistributionSourcePackageInDatabase.sourcepackagename ==
689
DistributionSourcePackageInDatabase.distribution ==
691
dsp_cache_key = distribution.id, sourcepackagename.id
693
pass # No way to eject things from the cache!
695
cls._cache[dsp_cache_key] = dsp.id
699
def new(cls, distribution, sourcepackagename,
700
is_upstream_link_allowed=False):
701
"""Create a new DSP with the given parameters.
703
Caches the `(distro_id, spn_id) --> dsp_id` mapping.
705
dsp = DistributionSourcePackageInDatabase()
706
dsp.distribution = distribution
707
dsp.sourcepackagename = sourcepackagename
708
dsp.is_upstream_link_allowed = is_upstream_link_allowed
709
Store.of(distribution).add(dsp)
710
Store.of(distribution).flush()
711
dsp_cache_key = distribution.id, sourcepackagename.id
712
cls._cache[dsp_cache_key] = dsp.id