2 {-# LANGUAGE NamedFieldPuns #-}
3 {-# LANGUAGE RecordWildCards #-}
5 -- | Management for the installed package store.
6 module Distribution
.Client
.Store
7 ( -- * The store layout
9 , defaultStoreDirLayout
11 -- * Reading store entries
15 -- * Creating store entries
17 , NewStoreEntryOutcome
(..)
19 -- * Concurrency strategy
23 import Distribution
.Client
.Compat
.Prelude
26 import Distribution
.Client
.DistDirLayout
27 import Distribution
.Client
.RebuildMonad
29 import Distribution
.Package
(UnitId
, mkUnitId
)
30 import Distribution
.Simple
.Compiler
(Compiler
(..))
32 import Distribution
.Simple
.Utils
37 import Distribution
.Verbosity
41 import Control
.Exception
42 import qualified Data
.Set
as Set
43 import System
.Directory
44 import System
.FilePath
46 #ifdef MIN_VERSION_lukko
49 import System
.IO (openFile, IOMode(ReadWriteMode
), hClose)
50 import GHC
.IO.Handle.Lock
(hLock
, hTryLock
, LockMode
(ExclusiveLock
))
51 import GHC
.IO.Handle.Lock
(hUnlock
)
56 -- We access and update the store concurrently. Our strategy to do that safely
59 -- The store entries once created are immutable. This alone simplifies matters
62 -- Additionally, the way 'UnitId' hashes are constructed means that if a store
63 -- entry exists already then we can assume its content is ok to reuse, rather
64 -- than having to re-recreate. This is the nix-style input hashing concept.
66 -- A consequence of this is that with a little care it is /safe/ to race
67 -- updates against each other. Consider two independent concurrent builds that
68 -- both want to build a particular 'UnitId', where that entry does not yet
69 -- exist in the store. It is safe for both to build and try to install this
70 -- entry into the store provided that:
72 -- * only one succeeds
73 -- * the looser discovers that they lost, they abandon their own build and
74 -- re-use the store entry installed by the winner.
76 -- Note that because builds are not reproducible in general (nor even
77 -- necessarily ABI compatible) then it is essential that the loser abandon
78 -- their build and use the one installed by the winner, so that subsequent
79 -- packages are built against the exact package from the store rather than some
80 -- morally equivalent package that may not be ABI compatible.
82 -- Our overriding goal is that store reads be simple, cheap and not require
83 -- locking. We will derive our write-side protocol to make this possible.
85 -- The read-side protocol is simply:
87 -- * check for the existence of a directory entry named after the 'UnitId' in
88 -- question. That is, if the dir entry @$root/foo-1.0-fe56a...@ exists then
89 -- the store entry can be assumed to be complete and immutable.
91 -- Given our read-side protocol, the final step on the write side must be to
92 -- atomically rename a fully-formed store entry directory into its final
93 -- location. While this will indeed be the final step, the preparatory steps
94 -- are more complicated. The tricky aspect is that the store also contains a
95 -- number of shared package databases (one per compiler version). Our read
96 -- strategy means that by the time we install the store dir entry the package
97 -- db must already have been updated. We cannot do the package db update
98 -- as part of atomically renaming the store entry directory however. Furthermore
99 -- it is not safe to allow either package db update because the db entry
100 -- contains the ABI hash and this is not guaranteed to be deterministic. So we
101 -- must register the new package prior to the atomic dir rename. Since this
102 -- combination of steps are not atomic then we need locking.
104 -- The write-side protocol is:
106 -- * Create a unique temp dir and write all store entry files into it.
108 -- * Take a lock named after the 'UnitId' in question.
110 -- * Once holding the lock, check again for the existence of the final store
111 -- entry directory. If the entry exists then the process lost the race and it
112 -- must abandon, unlock and re-use the existing store entry. If the entry
113 -- does not exist then the process won the race and it can proceed.
115 -- * Register the package into the package db. Note that the files are not in
116 -- their final location at this stage so registration file checks may need
119 -- * Atomically rename the temp dir to the final store entry location.
121 -- * Release the previously-acquired lock.
123 -- Obviously this means it is possible to fail after registering but before
124 -- installing the store entry, leaving a dangling package db entry. This is not
125 -- much of a problem because this entry does not determine package existence
126 -- for cabal. It does mean however that the package db update should be insert
127 -- or replace, i.e. not failing if the db entry already exists.
129 -- | Check if a particular 'UnitId' exists in the store.
130 doesStoreEntryExist
:: StoreDirLayout
-> Compiler
-> UnitId
-> IO Bool
131 doesStoreEntryExist StoreDirLayout
{storePackageDirectory
} compiler unitid
=
132 doesDirectoryExist (storePackageDirectory compiler unitid
)
134 -- | Return the 'UnitId's of all packages\/components already installed in the
136 getStoreEntries
:: StoreDirLayout
-> Compiler
-> Rebuild
(Set UnitId
)
137 getStoreEntries StoreDirLayout
{storeDirectory
} compiler
= do
138 paths
<- getDirectoryContentsMonitored
(storeDirectory compiler
)
139 return $! mkEntries paths
142 Set
.delete (mkUnitId
"package.db")
143 . Set
.delete (mkUnitId
"incoming")
147 valid
('.' : _
) = False
150 -- | The outcome of 'newStoreEntry': either the store entry was newly created
151 -- or it existed already. The latter case happens if there was a race between
152 -- two builds of the same store entry.
153 data NewStoreEntryOutcome
155 | UseExistingStoreEntry
158 -- | Place a new entry into the store. See the concurrency strategy description
161 -- In particular, it takes two actions: one to place files into a temporary
162 -- location, and a second to perform any necessary registration. The first
163 -- action is executed without any locks held (the temp dir is unique). The
164 -- second action holds a lock that guarantees that only one cabal process is
165 -- able to install this store entry. This means it is safe to register into
166 -- the compiler package DB or do other similar actions.
168 -- Note that if you need to use the registration information later then you
169 -- /must/ check the 'NewStoreEntryOutcome' and if it's'UseExistingStoreEntry'
170 -- then you must read the existing registration information (unless your
171 -- registration information is constructed fully deterministically).
177 -> (FilePath -> IO (FilePath, [FilePath]))
178 -- ^ Action to place files.
180 -- ^ Register action, if necessary.
181 -> IO NewStoreEntryOutcome
184 storeDirLayout
@StoreDirLayout
{..}
189 -- See $concurrency above for an explanation of the concurrency protocol
191 withTempIncomingDir storeDirLayout compiler
$ \incomingTmpDir
-> do
192 -- Write all store entry files within the temp dir and return the prefix.
193 (incomingEntryDir
, otherFiles
) <- copyFiles incomingTmpDir
195 -- Take a lock named after the 'UnitId' in question.
196 withIncomingUnitIdLock verbosity storeDirLayout compiler unitid
$ do
197 -- Check for the existence of the final store entry directory.
198 exists
<- doesStoreEntryExist storeDirLayout compiler unitid
201 then -- If the entry exists then we lost the race and we must abandon,
202 -- unlock and re-use the existing store entry.
205 "Concurrent build race: abandoning build in favour of existing "
208 </> prettyShow unitid
209 return UseExistingStoreEntry
210 else -- If the entry does not exist then we won the race and can proceed.
212 -- Register the package into the package db (if appropriate).
215 -- Atomically rename the temp dir to the final store entry location.
216 renameDirectory incomingEntryDir finalEntryDir
217 for_ otherFiles
$ \file
-> do
218 let finalStoreFile
= storeDirectory compiler
</> makeRelative
(normalise
$ incomingTmpDir
</> (dropDrive
(storeDirectory compiler
))) file
219 createDirectoryIfMissing
True (takeDirectory finalStoreFile
)
220 renameFile file finalStoreFile
223 "Installed store entry " ++ prettyShow compid
</> prettyShow unitid
224 return UseNewStoreEntry
226 compid
= compilerId compiler
228 finalEntryDir
= storePackageDirectory compiler unitid
233 -> (FilePath -> IO a
)
235 withTempIncomingDir StoreDirLayout
{storeIncomingDirectory
} compiler action
= do
236 createDirectoryIfMissing
True incomingDir
237 withTempDirectory silent incomingDir
"new" action
239 incomingDir
= storeIncomingDirectory compiler
241 withIncomingUnitIdLock
248 withIncomingUnitIdLock
250 StoreDirLayout
{storeIncomingLock
}
254 bracket takeLock releaseLock
(\_hnd
-> action
)
256 compid
= compilerId compiler
257 #ifdef MIN_VERSION_lukko
259 | fileLockingSupported
= do
260 fd
<- fdOpen
(storeIncomingLock compiler unitid
)
261 gotLock
<- fdTryLock fd ExclusiveLock
263 info verbosity
$ "Waiting for file lock on store entry "
264 ++ prettyShow compid
</> prettyShow unitid
265 fdLock fd ExclusiveLock
268 -- if there's no locking, do nothing. Be careful on AIX.
269 |
otherwise = return undefined -- :(
272 | fileLockingSupported
= do
275 |
otherwise = return ()
278 h
<- openFile (storeIncomingLock compiler unitid
) ReadWriteMode
279 -- First try non-blocking, but if we would have to wait then
280 -- log an explanation and do it again in blocking mode.
281 gotlock
<- hTryLock h ExclusiveLock
283 info verbosity
$ "Waiting for file lock on store entry "
284 ++ prettyShow compid
</> prettyShow unitid
285 hLock h ExclusiveLock
288 releaseLock h
= hUnlock h
>> hClose h