Browse Source

Cache resolved RevCommit in DefaultGitSyncService to avoid redundant resolveCommit calls

Resolve the commit once in onUpdate() and reuse the cached RevCommit
for listFiles and getFileContent operations, instead of resolving
the branch ref on every call. Added RevCommit-accepting overloads
to GitRepository for listFilesAtCommit and getFileContentAtCommit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pull/15064/head
Viacheslav Klimov 8 months ago
parent
commit
2ec6da3c56
Failed to extract signature
  1. 16
      application/src/main/java/org/thingsboard/server/service/sync/DefaultGitSyncService.java
  2. 35
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

16
application/src/main/java/org/thingsboard/server/service/sync/DefaultGitSyncService.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.sync;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.revwalk.RevCommit;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardExecutors;
@ -47,6 +48,8 @@ public class DefaultGitSyncService implements GitSyncService {
private final Map<String, GitRepository> repositories = new ConcurrentHashMap<>(); private final Map<String, GitRepository> repositories = new ConcurrentHashMap<>();
private final Map<String, Runnable> updateListeners = new ConcurrentHashMap<>(); private final Map<String, Runnable> updateListeners = new ConcurrentHashMap<>();
private RevCommit lastCommit;
@Override @Override
public void registerSync(String key, String repoUri, String branch, long fetchFrequencyMs, Runnable onUpdate) { public void registerSync(String key, String repoUri, String branch, long fetchFrequencyMs, Runnable onUpdate) {
RepositorySettings settings = new RepositorySettings(); RepositorySettings settings = new RepositorySettings();
@ -84,7 +87,7 @@ public class DefaultGitSyncService implements GitSyncService {
@Override @Override
public List<RepoFile> listFiles(String key, String path, int depth, FileType type) { public List<RepoFile> listFiles(String key, String path, int depth, FileType type) {
GitRepository repository = getRepository(key); GitRepository repository = getRepository(key);
return repository.listFilesAtCommit(getBranchRef(repository), path, depth).stream() return repository.listFilesAtCommit(lastCommit, path, depth).stream()
.filter(file -> type == null || file.type() == type) .filter(file -> type == null || file.type() == type)
.toList(); .toList();
} }
@ -93,7 +96,7 @@ public class DefaultGitSyncService implements GitSyncService {
@Override @Override
public byte[] getFileContent(String key, String path) { public byte[] getFileContent(String key, String path) {
GitRepository repository = getRepository(key); GitRepository repository = getRepository(key);
return repository.getFileContentAtCommit(path, getBranchRef(repository)); return repository.getFileContentAtCommit(path, lastCommit);
} }
@Override @Override
@ -137,6 +140,15 @@ public class DefaultGitSyncService implements GitSyncService {
} }
private void onUpdate(String key) { private void onUpdate(String key) {
GitRepository repository = getRepository(key);
String branchRef = getBranchRef(repository);
try {
lastCommit = repository.resolveCommit(branchRef);
} catch (Throwable e) {
log.error("[{}] Failed to resolve commit for ref {}", key, branchRef, e);
return;
}
Runnable listener = updateListeners.get(key); Runnable listener = updateListeners.get(key);
if (listener != null) { if (listener != null) {
log.debug("[{}] Handling repository update", key); log.debug("[{}] Handling repository update", key);

35
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

@ -277,13 +277,17 @@ public class GitRepository {
return listFilesAtCommit(commitId, path, -1).stream().map(RepoFile::path).toList(); return listFilesAtCommit(commitId, path, -1).stream().map(RepoFile::path).toList();
} }
@SneakyThrows
public List<RepoFile> listFilesAtCommit(String commitId, String path, int depth) { public List<RepoFile> listFilesAtCommit(String commitId, String path, int depth) {
log.debug("Executing listFilesAtCommit [{}][{}][{}]", settings.getRepositoryUri(), commitId, path); RevCommit commit = resolveCommit(commitId);
return listFilesAtCommit(commit, path, depth);
}
@SneakyThrows
public List<RepoFile> listFilesAtCommit(RevCommit commit, String path, int depth) {
log.debug("Executing listFilesAtCommit [{}][{}][{}]", settings.getRepositoryUri(), commit, path);
List<RepoFile> files = new ArrayList<>(); List<RepoFile> files = new ArrayList<>();
RevCommit revCommit = resolveCommit(commitId);
try (TreeWalk treeWalk = new TreeWalk(git.getRepository())) { try (TreeWalk treeWalk = new TreeWalk(git.getRepository())) {
treeWalk.reset(revCommit.getTree().getId()); treeWalk.reset(commit.getTree().getId());
if (StringUtils.isNotEmpty(path)) { if (StringUtils.isNotEmpty(path)) {
treeWalk.setFilter(PathFilter.create(path)); treeWalk.setFilter(PathFilter.create(path));
} }
@ -301,11 +305,15 @@ public class GitRepository {
return files; return files;
} }
@SneakyThrows
public byte[] getFileContentAtCommit(String file, String commitId) { public byte[] getFileContentAtCommit(String file, String commitId) {
log.debug("Executing getFileContentAtCommit [{}][{}][{}]", settings.getRepositoryUri(), commitId, file); RevCommit commit = resolveCommit(commitId);
RevCommit revCommit = resolveCommit(commitId); return getFileContentAtCommit(file, commit);
try (TreeWalk treeWalk = TreeWalk.forPath(git.getRepository(), file, revCommit.getTree())) { }
@SneakyThrows
public byte[] getFileContentAtCommit(String file, RevCommit commit) {
log.debug("Executing getFileContentAtCommit [{}][{}][{}]", settings.getRepositoryUri(), commit, file);
try (TreeWalk treeWalk = TreeWalk.forPath(git.getRepository(), file, commit.getTree())) {
if (treeWalk == null) { if (treeWalk == null) {
throw new IllegalArgumentException("File not found"); throw new IllegalArgumentException("File not found");
} }
@ -373,9 +381,9 @@ public class GitRepository {
for (RemoteRefUpdate update : pushResult.getRemoteUpdates()) { for (RemoteRefUpdate update : pushResult.getRemoteUpdates()) {
RemoteRefUpdate.Status status = update.getStatus(); RemoteRefUpdate.Status status = update.getStatus();
if (status == REJECTED_NONFASTFORWARD || status == REJECTED_NODELETE || if (status == REJECTED_NONFASTFORWARD || status == REJECTED_NODELETE ||
status == REJECTED_REMOTE_CHANGED || status == REJECTED_OTHER_REASON) { status == REJECTED_REMOTE_CHANGED || status == REJECTED_OTHER_REASON) {
throw new RuntimeException("Remote repository answered with error: " + throw new RuntimeException("Remote repository answered with error: " +
Optional.ofNullable(update.getMessage()).orElseGet(status::name)); Optional.ofNullable(update.getMessage()).orElseGet(status::name));
} }
} }
}); });
@ -450,7 +458,8 @@ public class GitRepository {
revCommit.getFullMessage(), revCommit.getAuthorIdent().getName(), revCommit.getAuthorIdent().getEmailAddress()); revCommit.getFullMessage(), revCommit.getAuthorIdent().getName(), revCommit.getAuthorIdent().getEmailAddress());
} }
private RevCommit resolveCommit(String id) throws IOException { @SneakyThrows
public RevCommit resolveCommit(String id) {
return git.getRepository().parseCommit(resolve(id)); return git.getRepository().parseCommit(resolve(id));
} }
@ -481,8 +490,8 @@ public class GitRepository {
private static final Function<PageLink, Comparator<RevCommit>> revCommitComparatorFunction = pageLink -> { private static final Function<PageLink, Comparator<RevCommit>> revCommitComparatorFunction = pageLink -> {
SortOrder sortOrder = pageLink.getSortOrder(); SortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null if (sortOrder != null
&& sortOrder.getProperty().equals("timestamp") && sortOrder.getProperty().equals("timestamp")
&& SortOrder.Direction.ASC.equals(sortOrder.getDirection())) { && SortOrder.Direction.ASC.equals(sortOrder.getDirection())) {
return Comparator.comparingInt(RevCommit::getCommitTime); return Comparator.comparingInt(RevCommit::getCommitTime);
} }
return null; return null;

Loading…
Cancel
Save