]> gitweb @ CieloNegro.org - Rakka.git/blobdiff - Rakka/Storage.hs
Wrote more
[Rakka.git] / Rakka / Storage.hs
index fc5637d7b686dff5a6eefc900132e4641c7f5760..6b0e098e883eedad9908154edea5205308912e38 100644 (file)
@@ -13,23 +13,24 @@ module Rakka.Storage
 
 import           Control.Arrow.ArrowIO
 import           Control.Concurrent.STM
+import           Control.Exception
 import           Control.Monad
 import           Control.Monad.Trans
 import           Data.Set (Set)
+import qualified Data.Set as S
 import           Rakka.Page
 import           Rakka.Storage.DefaultPage
 import           Subversion.Types
 import           System.Directory
 import           System.FilePath
+import           System.IO
 import           System.Log.Logger
+import           System.Posix.Files
+import           System.Posix.Types
+import           System.Posix.IO
+import           Subversion.FileSystem
 import           Subversion.Repository
-import           Text.HyperEstraier
-
--- FIXME
-import Data.Encoding
-import Data.Encoding.UTF8
-import qualified Data.ByteString.Lazy.Char8 as C8
--- FIXME
+import           Text.HyperEstraier hiding (WriteLock)
 
 logger = "Rakka.Storage"
 
@@ -46,8 +47,8 @@ data Storage
 
 mkStorage :: FilePath -> Repository -> (Page -> IO Document) -> IO Storage
 mkStorage lsdir repos mkDraft
-    = do let indexDir = lsdir `combine` "index"
-             revFile  = lsdir `combine` "indexRev"
+    = do let indexDir = lsdir </> "index"
+             revFile  = lsdir </> "indexRev"
              
          revLocked <- newTVarIO False
          indexDB   <- openIndex indexDir revFile
@@ -64,29 +65,45 @@ mkStorage lsdir repos mkDraft
          return sto
 
 
-getPage :: MonadIO m => Storage -> PageName -> m (Maybe Page)
-getPage sto name
-    = liftIO $ loadDefaultPage name -- FIXME
+getPage :: MonadIO m => Storage -> PageName -> Maybe RevNum -> m (Maybe Page)
+getPage = ((liftIO .) .) . getPage' . stoRepository
+
+
+getPage' :: Repository -> PageName -> Maybe RevNum -> IO (Maybe Page)
+getPage' repos name rev
+    = loadDefaultPage name -- FIXME
 
 
-putPage :: MonadIO m => Storage -> Maybe RevNum -> Page -> m ()
-putPage sto oldRev page
+putPage :: MonadIO m => Storage -> Page -> RevNum -> m ()
+putPage sto page oldRev
     = error "FIXME: not implemented"
 
 
-getPageA :: ArrowIO a => Storage -> a PageName (Maybe Page)
-getPageA = arrIO . getPage 
+getPageA :: ArrowIO a => Storage -> a (PageName, Maybe RevNum) (Maybe Page)
+getPageA = arrIO2 . getPage 
 
 
-putPageA :: ArrowIO a => Storage -> a (Maybe RevNum, Page) ()
+putPageA :: ArrowIO a => Storage -> a (Page, RevNum) ()
 putPageA = arrIO2 . putPage
 
 
 findAllPages :: Storage -> RevNum -> IO (Set PageName)
-findAllPages sto revNum
+findAllPages _   0   = findAllDefaultPages
+findAllPages sto rev
     = findAllDefaultPages -- FIXME
 
 
+findChangedPages :: Storage -> RevNum -> RevNum -> IO (Set PageName)
+findChangedPages sto 0      newRev = findAllPages sto newRev
+findChangedPages sto oldRev newRev
+    = fail "FIXME: not impl"
+
+
+getCurrentRevNum :: Storage -> IO RevNum
+getCurrentRevNum sto
+    = getRepositoryFS (stoRepository sto) >>= getYoungestRev
+
+
 -- casket を R/W モードで開く。成功したらそのまま返し、失敗したら
 -- indexDir と revFile を削除してから casket を R/W モードで開く。
 openIndex :: FilePath -> FilePath -> IO Database
@@ -117,8 +134,76 @@ openIndex indexDir revFile
 
 syncIndex :: Storage -> IO ()
 syncIndex sto
-    = do Just page <- getPage sto "MainPage"
-         doc       <- stoMakeDraft sto page
-         putStrLn "*** dumping draft..."
-         dumpDraft doc >>= C8.putStr . encodeLazy UTF8
-         putStrLn "*** dumped"
\ No newline at end of file
+    = updateIndexRev sto $ \ oldRev ->
+      do debugM logger ("The index revision is currently " ++ show oldRev)
+         
+         newRev <- getCurrentRevNum sto
+         debugM logger ("The repository revision is currently " ++ show newRev)
+
+         when (newRev /= oldRev) (syncIndex' oldRev newRev)
+         return newRev
+    where
+      syncIndex' :: RevNum -> RevNum -> IO ()
+      syncIndex' oldRev newRev
+          = do pages <- findChangedPages sto oldRev newRev
+               mapM_ (updateIndex sto newRev) (S.toList pages)
+
+
+updateIndex :: Storage -> RevNum -> PageName -> IO ()
+updateIndex sto rev name
+    = do pageM <- getPage sto name (Just rev)
+         case pageM of
+           -- ページが削除された
+           Nothing
+               -> do docIdM <- getDocIdByURI (stoIndexDB sto) (mkRakkaURI name)
+                     case docIdM of
+                       Nothing    -> return ()
+                       Just docId -> do removeDocument (stoIndexDB sto) docId [CleaningRemove]
+                                        infoM logger ("Removed page " ++ name ++ " from the index")
+           Just page
+               -> do draft <- stoMakeDraft sto page
+                     putDocument (stoIndexDB sto) draft [CleaningPut]
+                     infoM logger ("Indexed page " ++ name ++ " of revision " ++ show (pageRevision page))
+
+
+updateIndexRev :: Storage -> (RevNum -> IO RevNum) -> IO ()
+updateIndexRev sto f = bracket acquireLock releaseLock update
+    where
+      acquireLock :: IO Fd
+      acquireLock
+          = do atomically $ do revLocked <- readTVar (stoIndexRevLocked sto)
+                               if revLocked then
+                                   retry
+                                 else
+                                   writeTVar (stoIndexRevLocked sto) True
+               fd <- openFd (stoIndexRevFile sto) ReadWrite (Just stdFileMode) defaultFileFlags
+               waitToSetLock fd (WriteLock, AbsoluteSeek, 0, 0)
+               return fd
+
+      releaseLock :: Fd -> IO ()
+      releaseLock fd
+          = do setLock fd (Unlock, AbsoluteSeek, 0, 0)
+               atomically $ writeTVar (stoIndexRevLocked sto) False
+
+      update :: Fd -> IO ()
+      update fd
+          = do fdSeek fd AbsoluteSeek 0
+               size <- return . fromIntegral . fileSize =<< getFdStatus fd
+               (revStr, gotSize) <- fdRead fd size
+               when (size /= gotSize) $ fail ("read " ++ show gotSize ++
+                                              " bytes but expected " ++ show size ++ " bytes")
+               
+               let rev = case revStr of
+                           "" -> 0
+                           _  -> read revStr
+
+               rev' <- f rev
+
+               let revStr' = show rev' ++ "\n"
+                   size'   = fromIntegral $ length revStr'
+
+               fdSeek fd AbsoluteSeek 0
+               setFdSize fd 0
+               wroteSize <- fdWrite fd revStr'
+               when (size' /= wroteSize) $ fail ("wrote " ++ show wroteSize ++
+                                                 " bytes but expected " ++ show size' ++ " bytes")
\ No newline at end of file