Just wanted to ask: Do we need a millisecond precision in watchFileEx
(threadDelay 1000)?


On Tue, Dec 10, 2013 at 9:37 AM, Petr Pudlák <[email protected]> wrote:

> LGTM
>
> A minor idea, if you like it (no need to resend the patch, if you use it):
> It could be useful to make a named function for
>
>   liftM (either (const nullFStat) id) ((try $ getFStat fpath) :: IO
> (Either IOError FStat))
>
> it seems it'd be handy at other places as well.
>
>
> On Mon, Dec 9, 2013 at 5:01 PM, Klaus Aehlig <[email protected]> wrote:
>
>> Add a method to return the new value of a function if it changes within
>> the given timeout. If not, return the old value. Make use of the fact,
>> that the function only changes, if the specified file changes on disk.
>>
>> Signed-off-by: Klaus Aehlig <[email protected]>
>> ---
>>  src/Ganeti/Utils.hs | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 46 insertions(+)
>>
>> diff --git a/src/Ganeti/Utils.hs b/src/Ganeti/Utils.hs
>> index 3ebd103..47b2cea 100644
>> --- a/src/Ganeti/Utils.hs
>> +++ b/src/Ganeti/Utils.hs
>> @@ -69,16 +69,20 @@ module Ganeti.Utils
>>    , nullFStat
>>    , getFStat
>>    , needsReload
>> +  , watchFile
>>    ) where
>>
>> +import Control.Concurrent
>>  import Control.Exception (try)
>>  import Data.Char (toUpper, isAlphaNum, isDigit, isSpace)
>>  import Data.Function (on)
>> +import Data.IORef
>>  import Data.List
>>  import qualified Data.Map as M
>>  import Control.Monad (foldM, liftM)
>>  import System.Directory (renameFile)
>>  import System.FilePath.Posix (takeDirectory, takeBaseName)
>> +import System.INotify
>>  import System.Posix.Types
>>
>>  import Debug.Trace
>> @@ -575,3 +579,45 @@ needsReload oldstat path = do
>>    return $ if newstat /= oldstat
>>               then Just newstat
>>               else Nothing
>> +
>> +-- | Until the given point in time (useconds since the epoch), wait
>> +-- for the output of a given method to change and return the new value;
>> +-- make use of the promise that the output only changes if the reference
>> +-- has a value different than the given one.
>> +watchFileEx :: (Eq a, Eq b) => Integer -> b -> IORef b -> a -> IO a ->
>> IO a
>> +watchFileEx endtime base ref old read_fn = do
>> +  current <- getCurrentTimeUSec
>> +  if current > endtime then read_fn else do
>> +    val <- readIORef ref
>> +    if val /= base
>> +      then do
>> +        new <- read_fn
>> +        if new /= old then return new else do
>> +          threadDelay 1000
>> +          watchFileEx endtime val ref old read_fn
>> +      else do
>> +       threadDelay 1000
>> +       watchFileEx endtime base ref old read_fn
>> +
>> +-- | Within the given timeout (in seconds), wait for for the output
>> +-- of the given method to change and return the new value; make use of
>> +-- the promise that the method will only change its value, if
>> +-- the given file changes on disk. If the file does not exist on disk,
>> return
>> +-- immediately.
>> +watchFile :: Eq a => FilePath -> Int -> a -> IO a -> IO a
>> +watchFile fpath timeout old read_fn = do
>> +  current <- getCurrentTimeUSec
>> +  let endtime = current + fromIntegral timeout * 1000000
>> +  let fstat_fn = liftM (either (const nullFStat) id)
>> +                   ((try $ getFStat fpath) :: IO (Either IOError FStat))
>> +  fstat <- fstat_fn
>> +  ref <- newIORef fstat
>> +  inotify <- initINotify
>> +  _ <- addWatch inotify [Modify, Delete] fpath . const $ do
>> +    logDebug $ "Notified of change in " ++ fpath
>> +    fstat' <- fstat_fn
>> +    writeIORef ref fstat'
>> +  result <- watchFileEx endtime fstat ref old read_fn
>> +  killINotify inotify
>> +  return result
>> +
>> --
>> 1.8.5.1
>>
>>
>

Reply via email to