You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ir...@apache.org on 2020/06/03 18:14:54 UTC

[ignite-teamcity-bot] branch master updated: Cache and log cleaner (#162)

This is an automated email from the ASF dual-hosted git repository.

irakov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/master by this push:
     new d46d694  Cache and log cleaner (#162)
d46d694 is described below

commit d46d69427c15d822244bb579570183e844c9c317
Author: sergeyuttsel <ut...@gmail.com>
AuthorDate: Wed Jun 3 21:14:46 2020 +0300

    Cache and log cleaner (#162)
    
    Signed-off-by: Ivan Rakov <iv...@gmail.com>
---
 .../ci/tcbot/conf/LocalFilesBasedConfig.java       |   8 ++
 .../ignite/ci/web/rest/login/UserService.java      |   4 +
 .../ci/tcbot/chain/MockBasedTcBotModule.java       |   6 ++
 .../ignite/tcbot/engine/cleaner/Cleaner.java       | 115 +++++++++++++++++++++
 .../ignite/tcbot/engine/conf/CleanerConfig.java    |  41 ++++++++
 .../ignite/tcbot/engine/conf/ICleanerConfig.java   |  12 +++
 .../ignite/tcbot/engine/conf/ITcBotConfig.java     |   2 +
 .../ignite/tcbot/engine/conf/TcBotJsonConfig.java  |   6 ++
 .../tcbot/engine/defect/DefectCompacted.java       |   4 +
 .../ignite/tcbot/engine/defect/DefectsStorage.java |  20 ++++
 .../ignite/tcbot/engine/issue/IIssuesStorage.java  |   2 +
 .../ignite/tcbot/engine/issue/IssuesStorage.java   |  21 ++++
 .../ignited/buildcondition/BuildConditionDao.java  |   4 +
 .../apache/ignite/tcignited/build/FatBuildDao.java |  29 ++++++
 .../tcignited/buildlog/BuildLogCheckResultDao.java |   4 +
 .../ignite/tcignited/buildref/BuildRefDao.java     |   4 +
 .../tcignited/history/BuildStartTimeStorage.java   |   9 ++
 .../history/SuiteInvocationHistoryDao.java         |   4 +
 18 files changed, 295 insertions(+)

diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
index 6be47bc..d6ff6ec 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
@@ -32,7 +32,9 @@ import org.apache.ignite.tcbot.common.exeption.ExceptionUtil;
 import org.apache.ignite.tcbot.common.interceptor.GuavaCached;
 import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcbot.common.conf.TcBotWorkDir;
+import org.apache.ignite.tcbot.engine.conf.CleanerConfig;
 import org.apache.ignite.tcbot.engine.conf.GitHubConfig;
+import org.apache.ignite.tcbot.engine.conf.ICleanerConfig;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
 import org.apache.ignite.tcbot.engine.conf.ITrackedBranchesConfig;
 import org.apache.ignite.tcbot.engine.conf.JiraServerConfig;
@@ -142,4 +144,10 @@ public class LocalFilesBasedConfig implements ITcBotConfig {
         return HelperConfig.loadAuthProperties(workDir, cfgName);
     }
 
+    /** {@inheritDoc} */
+    @Override public ICleanerConfig getCleanerConfig() {
+        CleanerConfig cfg = getConfig().getCleanerConfig();
+        return cfg != null ? cfg : CleanerConfig.getDefaultCleanerConfig();
+    }
+
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
index d88f36f..b686414 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
@@ -32,6 +32,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Form;
 import javax.ws.rs.core.MediaType;
 import org.apache.ignite.ci.tcbot.ITcBotBgAuth;
+import org.apache.ignite.tcbot.engine.cleaner.Cleaner;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
 import org.apache.ignite.ci.tcbot.issue.IssueDetector;
 import org.apache.ignite.tcbot.engine.user.IUserStorage;
@@ -105,6 +106,9 @@ public class UserService {
 
         CtxListener.getInjector(ctx).getInstance(TcBotTriggerAndSignOffService.class).startObserver();
 
+        Cleaner cleaner = injector.getInstance(Cleaner.class);
+        cleaner.startBackgroundClean();
+
         return userMenu(prov,
             injector.getInstance(IUserStorage.class),
             issueDetector);
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
index 09d3677..f56522c 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
@@ -29,6 +29,8 @@ import org.apache.ignite.jiraignited.IJiraIgnited;
 import org.apache.ignite.jiraignited.IJiraIgnitedProvider;
 import org.apache.ignite.jiraservice.IJiraIntegration;
 import org.apache.ignite.jiraservice.IJiraIntegrationProvider;
+import org.apache.ignite.tcbot.engine.conf.CleanerConfig;
+import org.apache.ignite.tcbot.engine.conf.ICleanerConfig;
 import org.apache.ignite.tcbot.engine.conf.TcBotJsonConfig;
 import org.apache.ignite.githubservice.IGitHubConnection;
 import org.apache.ignite.githubservice.IGitHubConnectionProvider;
@@ -123,6 +125,10 @@ public class MockBasedTcBotModule extends AbstractModule {
             @Override public NotificationsConfig notifications() {
                 return new NotificationsConfig();
             }
+
+            @Override public ICleanerConfig getCleanerConfig() {
+                return CleanerConfig.getDefaultCleanerConfig();
+            }
         };
         bind(ITcBotConfig.class).toInstance(cfg);
         bind(IDataSourcesConfigSupplier.class).toInstance(cfg);
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/cleaner/Cleaner.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/cleaner/Cleaner.java
new file mode 100644
index 0000000..4460ffb
--- /dev/null
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/cleaner/Cleaner.java
@@ -0,0 +1,115 @@
+package org.apache.ignite.tcbot.engine.cleaner;
+
+import java.io.File;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.inject.Inject;
+import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildConditionDao;
+import org.apache.ignite.tcbot.common.conf.TcBotWorkDir;
+import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
+import org.apache.ignite.tcbot.common.interceptor.MonitoredTask;
+import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
+import org.apache.ignite.tcbot.engine.defect.DefectsStorage;
+import org.apache.ignite.tcbot.engine.issue.IIssuesStorage;
+import org.apache.ignite.tcignited.build.FatBuildDao;
+import org.apache.ignite.tcignited.buildlog.BuildLogCheckResultDao;
+import org.apache.ignite.tcignited.buildref.BuildRefDao;
+import org.apache.ignite.tcignited.history.BuildStartTimeStorage;
+import org.apache.ignite.tcignited.history.SuiteInvocationHistoryDao;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Cleaner {
+    @Inject IIssuesStorage issuesStorage;
+    @Inject FatBuildDao fatBuildDao;
+    @Inject SuiteInvocationHistoryDao suiteInvocationHistoryDao;
+    @Inject BuildLogCheckResultDao buildLogCheckResultDao;
+    @Inject BuildRefDao buildRefDao;
+    @Inject BuildStartTimeStorage buildStartTimeStorage;
+    @Inject BuildConditionDao buildConditionDao;
+    @Inject DefectsStorage defectsStorage;
+    @Inject ITcBotConfig cfg;
+
+    /** Logger. */
+    private static final Logger logger = LoggerFactory.getLogger(Cleaner.class);
+
+    private ScheduledExecutorService executorService;
+
+    @AutoProfiling
+    @MonitoredTask(name = "Clean ignite cache data and logs")
+    public void clean() {
+        if (cfg.getCleanerConfig().enabled()) {
+            try {
+                long safeDays = cfg.getCleanerConfig().safeDays();
+                int numOfItemsToDel = cfg.getCleanerConfig().numOfItemsToDel();
+                long thresholdDate = ZonedDateTime.now().minusDays(safeDays).toInstant().toEpochMilli();
+
+                removeCacheEntries(thresholdDate, numOfItemsToDel);
+                removeLogFiles(thresholdDate, numOfItemsToDel);
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+
+                logger.error("Periodic cache clean failed: " + e.getMessage(), e);
+            }
+        }
+        else
+            logger.info("Periodic cache clean disabled.");
+
+    }
+
+    private void removeCacheEntries(long thresholdDate, int numOfItemsToDel) {
+        List<Long> oldBuildsKeys = fatBuildDao.getOldBuilds(thresholdDate, numOfItemsToDel);
+
+        for (Long buildCacheKey : oldBuildsKeys) {
+            suiteInvocationHistoryDao.remove(buildCacheKey);
+            buildLogCheckResultDao.remove(buildCacheKey);
+            buildRefDao.remove(buildCacheKey);
+            buildStartTimeStorage.remove(buildCacheKey);
+            buildConditionDao.remove(buildCacheKey);
+            fatBuildDao.remove(buildCacheKey);
+        }
+
+        defectsStorage.removeOldDefects(thresholdDate, numOfItemsToDel);
+        issuesStorage.removeOldIssues(thresholdDate, numOfItemsToDel);
+    }
+
+    private void removeLogFiles(long thresholdDate, int numOfItemsToDel) {
+        final File workDir = TcBotWorkDir.resolveWorkDir();
+
+        for (String srvId : cfg.getServerIds()) {
+            File srvIdLogDir = new File(workDir, cfg.getTeamcityConfig(srvId).logsDirectory());
+            removeFiles(srvIdLogDir, thresholdDate, numOfItemsToDel);
+        }
+
+        File tcBotLogDir = new File(workDir, "tcbot_logs");
+        removeFiles(tcBotLogDir, thresholdDate, numOfItemsToDel);
+    }
+
+    private void removeFiles(File dir, long thresholdDate, int numOfItemsToDel) {
+        File[] logFiles = dir.listFiles();
+        if (logFiles != null)
+            for (File file : logFiles) {
+                if (file.lastModified() < thresholdDate && numOfItemsToDel-- > 0)
+                    file.delete();
+            }
+    }
+
+    public void startBackgroundClean() {
+        suiteInvocationHistoryDao.init();
+        buildLogCheckResultDao.init();
+        buildRefDao.init();
+        buildStartTimeStorage.init();
+        buildConditionDao.init();
+        fatBuildDao.init();
+
+        executorService = Executors.newSingleThreadScheduledExecutor();
+
+        executorService.scheduleAtFixedRate(this::clean, 30, 30, TimeUnit.MINUTES);
+//        executorService.scheduleAtFixedRate(this::clean, 0, 10, TimeUnit.SECONDS);
+
+    }
+}
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/CleanerConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/CleanerConfig.java
new file mode 100644
index 0000000..a97f093
--- /dev/null
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/CleanerConfig.java
@@ -0,0 +1,41 @@
+package org.apache.ignite.tcbot.engine.conf;
+
+public class CleanerConfig implements ICleanerConfig{
+    /** */
+    public static final int DEFAULT_SAVE_DAYS = 30 * 6;
+
+    /** */
+    public static final int DEFAULT_NUMBER_OF_ITEMS_TO_DELETE = 100;
+
+    /** */
+    private Integer safeDays;
+
+    /** */
+    private Integer numOfItemsToDel;
+
+    /** */
+    private Boolean enabled;
+
+    public static CleanerConfig getDefaultCleanerConfig() {
+        CleanerConfig cfg = new CleanerConfig();
+        cfg.safeDays = DEFAULT_SAVE_DAYS;
+        cfg.numOfItemsToDel = DEFAULT_NUMBER_OF_ITEMS_TO_DELETE;
+        cfg.enabled = true;
+        return cfg;
+    }
+
+    /** */
+    public int safeDays() {
+        return safeDays == null || safeDays < 0 ? DEFAULT_SAVE_DAYS : safeDays;
+    }
+
+    /** */
+    public int numOfItemsToDel() {
+        return numOfItemsToDel == null || numOfItemsToDel < 0 ? DEFAULT_NUMBER_OF_ITEMS_TO_DELETE : numOfItemsToDel;
+    }
+
+    /** */
+    public boolean enabled() {
+        return enabled == null ? true : enabled;
+    }
+}
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ICleanerConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ICleanerConfig.java
new file mode 100644
index 0000000..e19642d
--- /dev/null
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ICleanerConfig.java
@@ -0,0 +1,12 @@
+package org.apache.ignite.tcbot.engine.conf;
+
+public interface ICleanerConfig {
+    /** */
+    int safeDays();
+
+    /** */
+    int numOfItemsToDel();
+
+    /** */
+    boolean enabled();
+}
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
index 1d38a21..63e1448 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
@@ -67,4 +67,6 @@ public interface ITcBotConfig extends IDataSourcesConfigSupplier {
      * @return notification settings config.
      */
     public NotificationsConfig notifications();
+
+    public ICleanerConfig getCleanerConfig();
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
index 0fd0f24..be76dbc 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
@@ -53,6 +53,8 @@ public class TcBotJsonConfig implements ITrackedBranchesConfig {
     /** JIRA config to be used . */
     private List<GitHubConfig> gitHubConfigs = new ArrayList<>();
 
+    private CleanerConfig cleanerConfig;
+
     /** Notifications settings & tokens. */
     private NotificationsConfig notifications = new NotificationsConfig();
 
@@ -115,6 +117,10 @@ public class TcBotJsonConfig implements ITrackedBranchesConfig {
         return gitHubConfigs.stream().filter(s -> Objects.equals(code, s.getCode())).findAny();
     }
 
+    public CleanerConfig getCleanerConfig() {
+        return cleanerConfig;
+    }
+
     @Nullable
     public NotificationsConfig notifications() {
         return notifications;
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
index a397949..9e98d49 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
@@ -177,6 +177,10 @@ public class DefectCompacted {
         blameCandidates.removeIf(IVersionedEntity::isOutdatedEntityVersion);
     }
 
+    public long resolvedTs() {
+        return resolvedTs;
+    }
+
     /** {@inheritDoc} */
     @Override public boolean equals(Object o) {
         if (this == o)
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
index a66c606..23008bf 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
@@ -30,6 +30,7 @@ import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteAtomicSequence;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
@@ -173,4 +174,23 @@ public class DefectsStorage {
         Preconditions.checkState(defect.id() != 0);
         cache().put(defect.id(), defect);
     }
+
+    public void removeOldDefects(long thresholdDate, int numOfItemsToDel) {
+        IgniteCache<Integer, BinaryObject> cacheWithBinary = cache().withKeepBinary();
+
+        ScanQuery<Integer, BinaryObject> scan =
+            new ScanQuery<>((key, defect) -> {
+                long resolvedTs = defect.<Long>field("resolvedTs");
+                return resolvedTs > 0 && resolvedTs < thresholdDate;
+            });
+
+        for (Cache.Entry<Integer, BinaryObject> entry : cacheWithBinary.query(scan)) {
+            if (numOfItemsToDel > 0) {
+                numOfItemsToDel--;
+                cacheWithBinary.remove(entry.getKey());
+            }
+            else
+                break;
+        }
+    }
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IIssuesStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IIssuesStorage.java
index df19ae7..3cd3da9 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IIssuesStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IIssuesStorage.java
@@ -45,4 +45,6 @@ public interface IIssuesStorage {
     public boolean getIsNewAndSetNotified(IssueKey key, String addr, @Nullable Exception e);
 
     public void saveIssueSubscribersStat(IssueKey key, int cntSrvAllowed, int cntSubscribed, int cntTagsFilterPassed);
+
+    public void removeOldIssues(long thresholdDate, int numOfItemsToDel);
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssuesStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssuesStorage.java
index 1171db2..1e93c2b 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssuesStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssuesStorage.java
@@ -26,6 +26,8 @@ import javax.inject.Inject;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.ci.issue.Issue;
 import org.apache.ignite.ci.issue.IssueKey;
 import org.apache.ignite.tcbot.persistence.CacheConfigs;
@@ -125,4 +127,23 @@ public class IssuesStorage implements IIssuesStorage {
     @Override public Stream<Issue> allIssues() {
         return StreamSupport.stream(cache().spliterator(), false).map(Cache.Entry::getValue);
     }
+
+    public void removeOldIssues(long thresholdDate, int numOfItemsToDel) {
+        IgniteCache<BinaryObject, BinaryObject> cacheWithBinary = cache().withKeepBinary();
+
+        ScanQuery<BinaryObject, BinaryObject> scan =
+            new ScanQuery<>((issueKey, issue) -> {
+                Long detectedTs = issue.<Long>field("detectedTs");
+                return detectedTs != null && detectedTs < thresholdDate && detectedTs > 0;
+            });
+
+        for (Cache.Entry<BinaryObject, BinaryObject> entry : cacheWithBinary.query(scan)) {
+            if (numOfItemsToDel > 0) {
+                numOfItemsToDel--;
+                cacheWithBinary.remove(entry.getKey());
+            }
+            else
+                break;
+        }
+    }
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
index 0092037..476c881 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
@@ -75,4 +75,8 @@ public class BuildConditionDao {
 
         return false;
     }
+
+    public void remove(long key) {
+        buildsCache.remove(key);
+    }
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/FatBuildDao.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/FatBuildDao.java
index 197d2ad..889597e 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/FatBuildDao.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/FatBuildDao.java
@@ -19,7 +19,9 @@ package org.apache.ignite.tcignited.build;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -42,7 +44,9 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.CacheEntryProcessor;
 import org.apache.ignite.cache.affinity.Affinity;
+import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
 import org.apache.ignite.tcbot.persistence.CacheConfigs;
 import org.apache.ignite.tcbot.persistence.IStringCompactor;
@@ -402,6 +406,31 @@ public class FatBuildDao {
         }
     }
 
+    public List<Long> getOldBuilds(long thresholdDate, int numOfItemsToDel) {
+        IgniteCache<Long, BinaryObject> cacheWithBinary = buildsCache.withKeepBinary();
+
+        ScanQuery<Long, BinaryObject> scan = new ScanQuery<>((key, fatBuild) -> {
+                long startDate = fatBuild.<Long>field("startDate");
+                return startDate > 0 && startDate < thresholdDate;
+            }
+        );
+
+        List<Long> oldBuildsKeys = new ArrayList<>(numOfItemsToDel);
+        for (Cache.Entry<Long, BinaryObject> entry : cacheWithBinary.query(scan)) {
+            if (numOfItemsToDel > 0) {
+                numOfItemsToDel--;
+                oldBuildsKeys.add(entry.getKey());
+            }
+            else
+                break;
+        }
+        return oldBuildsKeys;
+    }
+
+    public void remove(long key) {
+        buildsCache.remove(key);
+    }
+
     /**
      * Returns Build Id if current build is missing in the cache.
      */
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildlog/BuildLogCheckResultDao.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildlog/BuildLogCheckResultDao.java
index db4816e..e1db997 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildlog/BuildLogCheckResultDao.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildlog/BuildLogCheckResultDao.java
@@ -58,4 +58,8 @@ public class BuildLogCheckResultDao {
     public void put(String srvCode, int buildId, LogCheckResultCompacted logCheckResultCompacted) {
         logsCache.put(getCacheKey(srvCode, buildId), logCheckResultCompacted);
     }
+
+    public void remove(long key) {
+        logsCache.remove(key);
+    }
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildref/BuildRefDao.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildref/BuildRefDao.java
index 368993e..715c3b5 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildref/BuildRefDao.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/buildref/BuildRefDao.java
@@ -364,4 +364,8 @@ public class BuildRefDao {
     public BuildRefCompacted get(int srvId, Integer buildId) {
         return buildRefsCache.get(buildIdToCacheKey(srvId, buildId));
     }
+
+    public void remove(long key) {
+        buildRefsCache.remove(key);
+    }
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/BuildStartTimeStorage.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/BuildStartTimeStorage.java
index fb4ec33..f4c344c 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/BuildStartTimeStorage.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/BuildStartTimeStorage.java
@@ -19,6 +19,7 @@ package org.apache.ignite.tcignited.history;
 
 import java.time.Duration;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -28,10 +29,14 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicIntegerArray;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
+import javax.cache.Cache;
 import javax.inject.Inject;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.tcbot.common.TcBotConst;
 import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
 import org.apache.ignite.tcbot.persistence.CacheConfigs;
@@ -181,4 +186,8 @@ public class BuildStartTimeStorage {
         return null;
     }
 
+    public void remove(long key) {
+        buildStartTime.remove(key);
+    }
+
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/SuiteInvocationHistoryDao.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/SuiteInvocationHistoryDao.java
index e62a4e5..96c10c4 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/SuiteInvocationHistoryDao.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/history/SuiteInvocationHistoryDao.java
@@ -91,4 +91,8 @@ public class SuiteInvocationHistoryDao {
 
         suiteHist.putAll(data);
     }
+
+    public void remove(long key) {
+        suiteHist.remove(key);
+    }
 }