summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Assistant/Threads/Committer.hs28
-rw-r--r--Utility/Lsof.hs4
-rw-r--r--Utility/SafeCommand.hs17
-rw-r--r--doc/design/assistant/android.mdwn5
4 files changed, 40 insertions, 14 deletions
diff --git a/Assistant/Threads/Committer.hs b/Assistant/Threads/Committer.hs
index 463c2965c..ba8d595f6 100644
--- a/Assistant/Threads/Committer.hs
+++ b/Assistant/Threads/Committer.hs
@@ -240,8 +240,7 @@ handleAdds delayadd cs = returnWhen (null incomplete) $ do
{- Files can Either be Right to be added now,
- or are unsafe, and must be Left for later.
-
- - Check by running lsof on the temp directory, which
- - the KeySources are locked down in.
+ - Check by running lsof on the repository.
-}
safeToAdd :: Maybe Seconds -> [Change] -> [Change] -> Assistant [Either Change Change]
safeToAdd _ [] [] = return []
@@ -249,12 +248,12 @@ safeToAdd delayadd pending inprocess = do
maybe noop (liftIO . threadDelaySeconds) delayadd
liftAnnex $ do
keysources <- mapM Command.Add.lockDown (map changeFile pending)
- let inprocess' = catMaybes $
- map mkinprocess (zip pending keysources)
- tmpdir <- fromRepo gitAnnexTmpDir
+ let inprocess' = inprocess ++ catMaybes (map mkinprocess $ zip pending keysources)
openfiles <- S.fromList . map fst3 . filter openwrite <$>
- liftIO (Lsof.queryDir tmpdir)
- let checked = map (check openfiles) $ inprocess ++ inprocess'
+ findopenfiles (map keySource inprocess')
+ liftIO $ print openfiles
+ let checked = map (check openfiles) inprocess'
+ liftIO $ print checked
{- If new events are received when files are closed,
- there's no need to retry any changes that cannot
@@ -290,3 +289,18 @@ safeToAdd delayadd pending inprocess = do
| otherwise = False
allRight = return . map Right
+
+ {- Normally the KeySources are locked down inside the temp directory,
+ - so can just lsof that, which is quite efficient.
+ -
+ - In crippled filesystem mode, there is no lock down, so must run lsof
+ - on each individual file.
+ -}
+ findopenfiles keysources = ifM crippledFileSystem
+ ( liftIO $ do
+ let segments = segmentXargs $ map keyFilename keysources
+ concat <$> forM segments (\fs -> Lsof.query $ "--" : fs)
+ , do
+ tmpdir <- fromRepo gitAnnexTmpDir
+ liftIO $ Lsof.queryDir tmpdir
+ )
diff --git a/Utility/Lsof.hs b/Utility/Lsof.hs
index 6e1d2f084..dd2914427 100644
--- a/Utility/Lsof.hs
+++ b/Utility/Lsof.hs
@@ -109,9 +109,9 @@ parseFormatted s = bundle $ go [] $ lines s
{- Parses lsof's default output format. -}
parseDefault :: LsofParser
-parseDefault = catMaybes . map parse . drop 1 . lines
+parseDefault = catMaybes . map parseline . drop 1 . lines
where
- parse l = case words l of
+ parseline l = case words l of
(command : spid : _user : _fd : _type : _device : _size : _node : rest) ->
case readish spid of
Nothing -> Nothing
diff --git a/Utility/SafeCommand.hs b/Utility/SafeCommand.hs
index 026456327..e6075e888 100644
--- a/Utility/SafeCommand.hs
+++ b/Utility/SafeCommand.hs
@@ -85,3 +85,20 @@ prop_idempotent_shellEscape :: String -> Bool
prop_idempotent_shellEscape s = [s] == (shellUnEscape . shellEscape) s
prop_idempotent_shellEscape_multiword :: [String] -> Bool
prop_idempotent_shellEscape_multiword s = s == (shellUnEscape . unwords . map shellEscape) s
+
+{- Segements a list of filenames into groups that are all below the manximum
+ - command-line length limit. Does not preserve order. -}
+segmentXargs :: [FilePath] -> [[FilePath]]
+segmentXargs l = go l [] 0 []
+ where
+ go [] c _ r = c:r
+ go (f:fs) c accumlen r
+ | len < maxlen && newlen > maxlen = go (f:fs) [] 0 (c:r)
+ | otherwise = go fs (f:c) newlen r
+ where
+ len = length f
+ newlen = accumlen + len
+
+ {- 10k of filenames per command, well under Linux's 20k limit;
+ - allows room for other parameters etc. -}
+ maxlen = 10240
diff --git a/doc/design/assistant/android.mdwn b/doc/design/assistant/android.mdwn
index cb82a40dc..79171c14c 100644
--- a/doc/design/assistant/android.mdwn
+++ b/doc/design/assistant/android.mdwn
@@ -20,11 +20,6 @@ is probably needed for at least older Android devices that have SD cards.
## TODO
-* In crippled filesystem mode, files are not hardlinked to a quarantine
- directory, so the assistant's use of lsof on that directory won't work.
- Instead, it should run lsof on the whole repository, and ignore other
- stuff. (Not really much slower even in a large repo, according to
- benchmarks.)
* rsync backend creates hard links
* migrate creates hard links between old and new keys
* avoid all symlink creation in crippled filesystem + direct mode