Skip to content
Permalink
Browse files
Time consuming builds detection: moved to async computation in scheduler
  • Loading branch information
dspavlov committed Jul 6, 2019
1 parent f88ba17 commit e0b4e780ee5bc976b583abf44189562457e1d910
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 175 deletions.
@@ -19,6 +19,7 @@
import com.google.inject.AbstractModule;
import com.google.inject.internal.SingletonScope;
import org.apache.ignite.ci.issue.IssuesStorage;
import org.apache.ignite.tcbot.engine.buildtime.BuildTimeService;
import org.apache.ignite.tcbot.engine.chain.BuildChainProcessor;
import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
import org.apache.ignite.ci.tcbot.conf.LocalFilesBasedConfig;
@@ -42,5 +43,8 @@ public class TcBotBusinessServicesModule extends AbstractModule {
bind(MasterTrendsService.class).in(new SingletonScope());
bind(ITcBotBgAuth.class).to(TcBotBgAuthImpl.class).in(new SingletonScope());
bind(BuildChainProcessor.class).in(new SingletonScope());

//todo move to bot engine module
bind(BuildTimeService.class).in(new SingletonScope());
}
}
@@ -40,7 +40,6 @@

$.ajax({ url: "/rest/buildtime/analytics",
success: function (data) {
$("#buildTime").html("Test");
$("#loadStatus").html("");
}, error: showErrInLoadStatus });
}
@@ -57,8 +56,6 @@
<a href="index0.html"><button class="idxpgbutton"><font size="30px">&lambda;</font><br>I like old home page</button></a>
</div>

<div id="buildTime"></div>

<div id="loadStatus"></div>
<div id="version"></div>

@@ -17,15 +17,13 @@

package org.apache.ignite.tcbot.engine.buildtime;

import org.apache.ignite.IgniteCache;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.tcbot.common.interceptor.MonitoredTask;
import org.apache.ignite.tcbot.common.util.TimeUtil;
import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
import org.apache.ignite.tcbot.engine.ui.BuildTimeRecordUi;
import org.apache.ignite.tcbot.engine.ui.BuildTimeResultUi;
import org.apache.ignite.tcbot.persistence.IStringCompactor;
import org.apache.ignite.tcbot.persistence.scheduler.IScheduler;
import org.apache.ignite.tcignited.ITeamcityIgnited;
import org.apache.ignite.tcignited.ITeamcityIgnitedProvider;
import org.apache.ignite.tcignited.build.FatBuildDao;
@@ -34,46 +32,42 @@
import org.apache.ignite.tcignited.buildtime.BuildTimeResult;
import org.apache.ignite.tcignited.creds.ICredentialsProv;
import org.apache.ignite.tcignited.history.HistoryCollector;
import org.apache.ignite.tcignited.history.RunHistCompactedDao;
import org.apache.ignite.tcservice.model.hist.BuildRef;
import org.apache.ignite.tcservice.model.result.stat.Statistics;

import javax.cache.Cache;
import javax.inject.Inject;
import java.time.Duration;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class BuildTimeService {

@Inject ITeamcityIgnitedProvider tcProv;

/** Config. */
@Inject ITcBotConfig cfg;

@Inject FatBuildDao fatBuildDao;

@Inject BuildRefDao buildRefDao;

@Inject RunHistCompactedDao runHistCompactedDao;

@Inject IStringCompactor compactor;

@Inject HistoryCollector historyCollector;

public BuildTimeResultUi analytics(ICredentialsProv prov) {
String serverCode = cfg.primaryServerCode();
@Inject IScheduler scheduler;

ITeamcityIgnited server = tcProv.server(serverCode, prov);
private volatile BuildTimeResult lastRes1d = new BuildTimeResult();

// fatBuildDao.loadBuildTimeResult();
@Inject private BuildRefDao buildRefDao;

Collection<String> allServers = cfg.getServerIds();
public BuildTimeResultUi analytics(ICredentialsProv prov) {
if (buildRefDao.buildRefsCache() == null)
return new BuildTimeResultUi();

int days = 1;
List<Long> idsToCheck = forEachBuildRef(days, allServers);
Collection<String> allServers = cfg.getServerIds();

BuildTimeResult res = fatBuildDao.loadBuildTimeResult(days, idsToCheck);
scheduler.sheduleNamed("BuildTimeService.loadAnalytics",
this::loadAnalytics, 15, TimeUnit.MINUTES);

Set<Integer> availableServers = allServers.stream()
.filter(prov::hasAccess)
@@ -83,8 +77,10 @@ public BuildTimeResultUi analytics(ICredentialsProv prov) {
BuildTimeResultUi resultUi = new BuildTimeResultUi();

long minDuration = Duration.ofHours(1).toMillis();
List<Map.Entry<Long, BuildTimeRecord>> entries = res.topBuildTypes(availableServers, minDuration);
entries.forEach(e->{
BuildTimeResult res = lastRes1d;
List<Map.Entry<Long, BuildTimeRecord>> entries = res.topByBuildTypes(availableServers, minDuration, 5);

entries.forEach(e -> {
BuildTimeRecordUi buildTimeRecordUi = new BuildTimeRecordUi();
Long key = e.getKey();
int btId = BuildTimeResult.cacheKeyToBuildType(key);
@@ -94,82 +90,18 @@ public BuildTimeResultUi analytics(ICredentialsProv prov) {
resultUi.byBuildType.add(buildTimeRecordUi);
});



return resultUi;
}

public List<Long> forEachBuildRef(int days, Collection<String> allServers) {
IgniteCache<Long, BinaryObject> cacheBin = buildRefDao.buildRefsCache().withKeepBinary();

Set<Integer> availableServers = allServers.stream()
.map(ITeamcityIgnited::serverIdToInt)
.collect(Collectors.toSet());

Map<Integer, Integer> preBorder = new HashMap<>();

availableServers.forEach(srvId -> {
Integer borderForAgeForBuildId = runHistCompactedDao.getBorderForAgeForBuildId(srvId, days);
if (borderForAgeForBuildId != null)
preBorder.put(srvId, borderForAgeForBuildId);
});

int stateRunning = compactor.getStringId(BuildRef.STATE_RUNNING);
final int stateQueued = compactor.getStringId(BuildRef.STATE_QUEUED);
Integer buildDurationId = compactor.getStringIdIfPresent(Statistics.BUILD_DURATION);

long minTs = System.currentTimeMillis() - Duration.ofDays(days).toMillis();
QueryCursor<Cache.Entry<Long, BinaryObject>> query = cacheBin.query(
new ScanQuery<Long, BinaryObject>()
.setFilter((key, v) -> {
int srvId = BuildRefDao.cacheKeyToSrvId(key);
Integer buildIdBorder = preBorder.get(srvId);
if (buildIdBorder != null) {
int id = v.field("id");
if (id < buildIdBorder)
return false;// pre-filtered build out of scope
}
int state = v.field("state");

return stateQueued != state;
}));

int cnt = 0;
List<Long> idsToCheck = new ArrayList<>();

try (QueryCursor<Cache.Entry<Long, BinaryObject>> cursor = query) {
for (Cache.Entry<Long, BinaryObject> next : cursor) {
Long key = next.getKey();
int srvId = BuildRefDao.cacheKeyToSrvId(key);

int buildId = BuildRefDao.cacheKeyToBuildId(key);

Integer borderBuildId = runHistCompactedDao.getBorderForAgeForBuildId(srvId, days);

boolean passesDate = borderBuildId == null || buildId >= borderBuildId;

if (!passesDate)
continue;

Long startTs = historyCollector.getBuildStartTime(srvId, buildId);
if (startTs == null || startTs < minTs)
continue; //time not saved in the DB, skip

BinaryObject buildBinary = next.getValue();
long runningTime = 0l;// getBuildRunningTime(stateRunning, buildDurationId, buildBinary);

System.err.println("Found build at srv [" + srvId + "]: [" + buildId + "] to analyze, ts="+ startTs);

cnt++;

idsToCheck.add(key);
}
}
@SuppressWarnings("WeakerAccess")
@MonitoredTask(name = "Load Build Time Analytics")
protected void loadAnalytics() {
int days = 1;

System.err.println("Total builds to load " + cnt);
List<Long> idsToCheck = historyCollector.findAllRecentBuilds(days, cfg.getServerIds());

// serversCompute.call(new BuildTimeIgniteCallable(cacheBin, stateRunning, buildDurationId));
BuildTimeResult res = fatBuildDao.loadBuildTimeResult(days, idsToCheck);

return idsToCheck;
lastRes1d = res;
}
}
@@ -322,51 +322,4 @@ public int[] getAllIds(int srvId) {
public IgniteCache<Long, BuildRefCompacted> buildRefsCache() {
return buildRefsCache;
}

public static class BuildTimeIgniteCallable implements IgniteCallable<Long> {
private final int stateRunning;
private final Integer buildDurationId;
@IgniteInstanceResource
Ignite ignite;

public BuildTimeIgniteCallable(IgniteCache<Long, BinaryObject> cacheBin, int stateRunning,
Integer buildDurationId) {
this.stateRunning = stateRunning;
this.buildDurationId = buildDurationId;
}

@Override public Long call() throws Exception {
IgniteCache<Long, BuildRefCompacted> cache = ignite.cache(TEAMCITY_BUILD_CACHE_NAME);

IgniteCache<Long, BuildRefCompacted>cacheBin = cache.withKeepBinary();
QueryCursor<Cache.Entry<Long, BinaryObject>> query = cacheBin.query(
new ScanQuery<Long, BinaryObject>()
.setFilter((k,v)->{
int srvId = cacheKeyToSrvId(k);

return false;
})
.setLocal(true));

/*.query(new SqlQuery<Long, BinaryObject>(
FatBuildCompacted.class,
" _KEY > ?")
.setLocal(true)
.setArgs(0L));*/

// Iterate over the result set.
try (QueryCursor<Cache.Entry<Long, BinaryObject>> cursor = query) {

for (Cache.Entry<Long, BinaryObject> next : cursor) {

BinaryObject buildBinary = next.getValue();
long runningTime = 0l;// getBuildRunningTime(stateRunning, buildDurationId, buildBinary);

System.err.println("Running " + runningTime);
}
}

return null;
}
}
}
@@ -26,25 +26,20 @@ public static int cacheKeyToBuildType(Long cacheKey) {
}


public List<Map.Entry<Long, BuildTimeRecord>> topBuildTypes(Set<Integer> availableServers, long minAvgDurationMs) {
public List<Map.Entry<Long, BuildTimeRecord>> topByBuildTypes(Set<Integer> availableServers,
long minAvgDurationMs,
int maxCnt) {
return btByBuildType.entrySet().stream()
.filter(e->{
.filter(e -> {
Long key = e.getKey();
int srvId = cacheKeyToSrvId(key);
return availableServers.contains(srvId);
})
.filter(e->{
return e.getValue().avgDuration() > minAvgDurationMs;
})
.sorted(Comparator.comparing(new Function<Map.Entry<Long, BuildTimeRecord>,
Long>() {
@Override
public Long apply( Map.Entry<Long, BuildTimeRecord> entry) {
return entry.getValue().avgDuration();
}
})
.reversed())
.limit(5)
.filter(e -> e.getValue().avgDuration() > minAvgDurationMs)
.sorted(Comparator.comparing(
(Function<Map.Entry<Long, BuildTimeRecord>, Long>) entry -> entry.getValue().avgDuration())
.reversed())
.limit(maxCnt)
.collect(Collectors.toList());
}
}

0 comments on commit e0b4e78

Please sign in to comment.