Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.

Commit

Permalink
Merge pull request #3698 from input-output-hk/adinapoli/feature/cbr-460
Browse files Browse the repository at this point in the history
[CBR-460] Improve the archive pruner
  • Loading branch information
adinapoli-iohk authored Oct 2, 2018
2 parents d191c77 + 731dc0f commit e3c42a9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 17 deletions.
4 changes: 4 additions & 0 deletions pkgs/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18120,6 +18120,7 @@ license = stdenv.lib.licenses.mit;
, string-conv
, swagger2
, tabl
, tar
, text
, time
, time-units
Expand All @@ -18136,6 +18137,7 @@ license = stdenv.lib.licenses.mit;
, x509
, x509-store
, yaml
, zlib
}:
mkDerivation {

Expand Down Expand Up @@ -18224,6 +18226,7 @@ sqlite-simple
sqlite-simple-errors
stm
swagger2
tar
text
time
time-units
Expand All @@ -18239,6 +18242,7 @@ wai-middleware-throttle
warp
x509
x509-store
zlib
];
executableHaskellDepends = [
aeson
Expand Down
2 changes: 2 additions & 0 deletions wallet-new/cardano-sl-wallet-new.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ library
, stm
, stm
, swagger2
, tar
, text
, time
, time-units
Expand All @@ -256,6 +257,7 @@ library
, warp
, x509
, x509-store
, zlib

default-language: Haskell2010
default-extensions: TypeOperators
Expand Down
73 changes: 56 additions & 17 deletions wallet-new/src/Cardano/Wallet/Server/Plugins/AcidState.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ import Universum

import Control.Concurrent (threadDelay)
import Data.Acid (AcidState, createArchive, createCheckpoint)
import qualified Data.ByteString.Lazy as B
import Data.List (isInfixOf)
import Data.Time (defaultTimeLocale, formatTime, getCurrentTime,
iso8601DateFormat)
import Data.Time.Units (Minute, toMicroseconds)
import System.Directory (getModificationTime, listDirectory,
removeFile)
import System.FilePath ((</>))

import qualified Codec.Archive.Tar as Tar
import qualified Codec.Compression.GZip as GZip

import Pos.Util.Wlog (logError, logInfo)

import Cardano.Wallet.Kernel (DatabaseMode (..), DatabaseOptions (..))
Expand All @@ -37,25 +44,57 @@ createAndArchiveCheckpoints dbRef delay dbMode =
go dbPath = do
logInfo "createAndArchiveCheckpoints is starting..."

res <- liftIO . try $ do
createCheckpoint dbRef
createArchive dbRef
res <- try $ do
liftIO (createCheckpoint dbRef >> createArchive dbRef)
pruneAndCompress 3 dbPath
case res of
Left (err :: SomeException) -> logError (show err)
Right () -> pruneOldArchives dbPath
Right () -> return ()

-- Wait for the next compaction cycle.
liftIO . threadDelay . fromInteger $ toMicroseconds delay
-- Prunes old acid-state archives.
pruneOldArchives :: FilePath -> Kernel.WalletMode ()
pruneOldArchives dbPath = liftIO $ do
let archiveDir = dbPath </> "Archive"
archiveCheckpoints <- map (archiveDir </>) <$> listDirectory archiveDir
-- same files, but newest first
newestFirst <-
map fst . reverse . sortWith snd <$>
mapM (\f -> (f,) <$> liftIO (getModificationTime f)) archiveCheckpoints
let oldFiles = drop 10 newestFirst
forM_ oldFiles removeFile

logInfo ("pruneOldArchives pruned " <> show (length oldFiles) <> " old archives.")

-- | Prunes old acid-state archives, keeping only the most @n@ recent of them.
-- After the clean-up it tar and gzip compressed them.
pruneAndCompress :: Int
-- ^ How many to keep.
-> FilePath
-- ^ The path to the database folder
-> Kernel.WalletMode ()
pruneAndCompress n dbPath = liftIO $ do
let archiveDir = dbPath </> "Archive"
fullRelPath = (archiveDir </>)
archives <- listDirectory archiveDir

newestFirst <-
map fst . reverse . sortWith snd <$>
sequence [(f,) <$> getModificationTime (fullRelPath f) | f <- archives]

-- Partition the files into @toPrune@ and @toCompress@ (the @n@ newest).
-- Filter from the first subset any previously-created tarball.
let (toCompress, toPrune) = first (filter (not . isTarball))
. splitAt n
$ newestFirst

-- Prune the old archives (including tarballs, if necessary).
mapM_ (removeFile . fullRelPath) toPrune
logInfo ("pruneAndCompress pruned " <> show (length toPrune) <> " old archives.")

now <- getCurrentTime
let tarName = "archive_"
<> formatTime defaultTimeLocale (iso8601DateFormat (Just "%H_%M_%S")) now
<> ".tar.gz"

-- Compress and archive (no pun intended) the rest.
-- As per documentation, 'Tar.pack' wants @toCompress@ to be relative paths
-- to @archiveDir@.
B.writeFile (archiveDir </> tarName) . GZip.compress
. Tar.write =<< Tar.pack archiveDir toCompress

logInfo ("pruneAndCompress compressed " <> show (length toCompress) <> " archives.")

-- Remove the archived files.
mapM_ (removeFile . fullRelPath) toCompress
where
isTarball :: FilePath -> Bool
isTarball fp = ".tar.gz" `isInfixOf` fp

0 comments on commit e3c42a9

Please sign in to comment.