diff options
-rw-r--r-- | Assistant/Threads/Committer.hs | 28 | ||||
-rw-r--r-- | Utility/Lsof.hs | 4 | ||||
-rw-r--r-- | Utility/SafeCommand.hs | 17 | ||||
-rw-r--r-- | doc/design/assistant/android.mdwn | 5 |
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 |