This is an automated email from the ASF dual-hosted git repository.
dspavlov 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 95c63c2a IGNITE-28630: Improve TC Bot diagnostics and add legacy DB
compatibility test (#211)
95c63c2a is described below
commit 95c63c2a5bb56092f19f59b86f1847135aaa16e4
Author: ignitetcbot <[email protected]>
AuthorDate: Fri May 8 20:22:07 2026 +0300
IGNITE-28630: Improve TC Bot diagnostics and add legacy DB compatibility
test (#211)
Add manual legacy DB compatibility perf test excluded from regular CI.
---
.gitignore | 2 +-
README.md | 3 +
migrator/build.gradle | 20 +++++
.../LegacyPersistentStorageCompatibilityTest.java | 87 +++++++++++++++++++++-
tcbot-engine/build.gradle | 2 +-
tcbot-github-ignited/build.gradle | 2 +-
tcbot-jira-ignited/build.gradle | 2 +-
tcbot-jira/build.gradle | 4 +-
tcbot-persistence/build.gradle | 2 +-
tcbot-teamcity-ignited/build.gradle | 4 +-
.../ignite/tcignited/buildref/BuildRefDao.java | 59 +++++++++++----
tcbot-teamcity/build.gradle | 4 +-
12 files changed, 163 insertions(+), 28 deletions(-)
diff --git a/.gitignore b/.gitignore
index dc3fbd97..b8938992 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,4 @@ hs_err_pid*
/conf/branches-prom.json
/ignite-tc-helper-web/ignite/**
/ignite-tc-helper-web/src/test/tmp/**
-/migrator/src/test/work/**
\ No newline at end of file
+/migrator/src/test/work/**
diff --git a/README.md b/README.md
index 5ca5ed51..1f7a2f69 100644
--- a/README.md
+++ b/README.md
@@ -125,3 +125,6 @@ be retried instead of silently leaving mixed old and new
data.
The same migrator can also be run as a standalone tool from the `migrator`
module against an Ignite work directory. The
standalone module uses the same Ignite version as the rest of the project
through the shared `ignVer` Gradle property.
+The heavyweight legacy storage compatibility/perf test is excluded from the
regular `:migrator:test` task. Run it
+explicitly with `./gradlew :migrator:legacyDbCompatPerfTest --no-daemon` when
checking old Ignite 2.14 persistent
+storage compatibility.
diff --git a/migrator/build.gradle b/migrator/build.gradle
index d47fd114..4e6a9140 100644
--- a/migrator/build.gradle
+++ b/migrator/build.gradle
@@ -26,6 +26,26 @@ test {
jvmArgs igniteJava17JvmArgs
maxHeapSize = '1536m'
systemProperty 'compat.work.dir',
file('src/test/work/ignite-db-compat').absolutePath
+ exclude '**/LegacyPersistentStorageCompatibilityTest.class'
+ failOnNoDiscoveredTests = false
+
+ testLogging {
+ events 'passed', 'failed', 'skipped', 'standardOut', 'standardError'
+ showStandardStreams = true
+ }
+}
+
+tasks.register('legacyDbCompatPerfTest', Test) {
+ description = 'Runs the heavyweight legacy Ignite persistent storage
compatibility/perf test.'
+ group = 'verification'
+
+ testClassesDirs = sourceSets.test.output.classesDirs
+ classpath = sourceSets.test.runtimeClasspath
+
+ jvmArgs igniteJava17JvmArgs
+ maxHeapSize = '1536m'
+ systemProperty 'compat.work.dir',
file('src/test/work/ignite-db-compat').absolutePath
+ include '**/LegacyPersistentStorageCompatibilityTest.class'
testLogging {
events 'passed', 'failed', 'skipped', 'standardOut', 'standardError'
diff --git
a/migrator/src/test/java/org/apache/ignite/migrate/LegacyPersistentStorageCompatibilityTest.java
b/migrator/src/test/java/org/apache/ignite/migrate/LegacyPersistentStorageCompatibilityTest.java
index 6dcd5d17..7c5cfb58 100644
---
a/migrator/src/test/java/org/apache/ignite/migrate/LegacyPersistentStorageCompatibilityTest.java
+++
b/migrator/src/test/java/org/apache/ignite/migrate/LegacyPersistentStorageCompatibilityTest.java
@@ -105,6 +105,9 @@ public class LegacyPersistentStorageCompatibilityTest {
/** Cache used only to produce enough WAL with old Ignite. */
private static final String LEGACY_WAL_STRESS_CACHE =
"legacyWalStressCache";
+ /** Current migration key that must be absent in the legacy marker set and
then applied by current code. */
+ private static final String GRID_INT_LIST_MIGRATION =
"migrate-GridIntList";
+
/** Small durable region for the test. */
private static final long REGION_SIZE = 256L * 1024 * 1024;
@@ -144,10 +147,15 @@ public class LegacyPersistentStorageCompatibilityTest {
ignite.cluster().active(true);
+ IgniteCache<String, Object> doneMigrations =
assertLegacyMigrationMarkersExist(ignite);
+
String migrationRes = runMigrationsWithFilteredOutput(ignite);
System.out.println("Migration result: " + migrationRes);
+ assertTrue("Current migrator must record the GridIntList
migration",
+ doneMigrations.containsKey(GRID_INT_LIST_MIGRATION));
+
PersistentStringCompactor compactor = new
PersistentStringCompactor(ignite);
int srvId = ITeamcityIgnited.serverIdToInt(SRV_ID);
@@ -172,6 +180,8 @@ public class LegacyPersistentStorageCompatibilityTest {
assertEquals(GridIntList.asList(1, 2, 3), migrated);
+ assertAllUserCachesCanBeDeserialized(ignite);
+
failureHandler.assertNoFailure();
}
finally {
@@ -225,7 +235,7 @@ public class LegacyPersistentStorageCompatibilityTest {
if (line.startsWith("cache [") && line.endsWith("] not found"))
missingCaches++;
- if (line.contains("migrate-GridIntList"))
+ if (line.contains(GRID_INT_LIST_MIGRATION))
gridIntListLines.add(line);
}
@@ -237,6 +247,74 @@ public class LegacyPersistentStorageCompatibilityTest {
assertTrue("GridIntList migration must run",
!gridIntListLines.isEmpty());
}
+ /**
+ * @param ignite Ignite.
+ * @return Existing done migrations cache created by the old bot code.
+ */
+ private IgniteCache<String, Object>
assertLegacyMigrationMarkersExist(Ignite ignite) {
+ String cacheName =
DbMigrations.ignCacheNme(DbMigrations.DONE_MIGRATIONS,
DbMigrations.DONE_MIGRATION_PREFIX);
+ IgniteCache<String, Object> doneMigrations = ignite.cache(cacheName);
+
+ assertNotNull("Legacy generator must create old migration markers
cache " + cacheName, doneMigrations);
+
+ int size = doneMigrations.size();
+
+ System.out.println("Legacy migration markers before current migrator:
" + size);
+
+ assertTrue("Legacy generator must execute old migrations and leave
done markers", size > 0);
+ assertFalse("Legacy marker set must not already skip the current
GridIntList migration",
+ doneMigrations.containsKey(GRID_INT_LIST_MIGRATION));
+
+ return doneMigrations;
+ }
+
+ /**
+ * @param ignite Ignite.
+ */
+ private void assertAllUserCachesCanBeDeserialized(Ignite ignite) {
+ int caches = 0;
+ long entries = 0;
+
+ for (String cacheName : ignite.cacheNames()) {
+ IgniteCache<Object, Object> cache = ignite.cache(cacheName);
+
+ if (cache == null)
+ continue;
+
+ caches++;
+
+ long cacheEntries = 0;
+
+ try {
+ for (Cache.Entry<Object, Object> entry : cache) {
+ Object key = entry.getKey();
+ Object val = entry.getValue();
+
+ if (key != null)
+ key.getClass();
+
+ if (val != null)
+ val.getClass();
+
+ cacheEntries++;
+ }
+ }
+ catch (RuntimeException | LinkageError e) {
+ throw new AssertionError("Unable to deserialize cache [" +
cacheName
+ + "] after migration, processedEntries=" + cacheEntries,
e);
+ }
+
+ entries += cacheEntries;
+
+ System.out.println("Deserialized cache [" + cacheName + "]
entries=" + cacheEntries);
+ }
+
+ System.out.println("Deserialized persistent caches: caches=" + caches
+ ", entries=" + entries);
+
+ assertTrue("At least one cache must be checked", caches > 0);
+ assertTrue("At least one cache entry must be checked", entries > 0);
+ }
+
/**
* @param line Migration log line.
* @return Migration procedure name.
@@ -539,6 +617,11 @@ public class LegacyPersistentStorageCompatibilityTest {
+ "\n"
+ " writeWalStressData(ignite);\n"
+ "\n"
+ + " String legacyMigrationRes = new
DbMigrations(ignite).dataMigration();\n"
+ + " IgniteCache<String, Object> doneMigrations =
ignite.cache(DbMigrations.ignCacheNme(DbMigrations.DONE_MIGRATIONS,
DbMigrations.DONE_MIGRATION_PREFIX));\n"
+ + " System.out.println(\"Legacy migrations result: \" +
legacyMigrationRes);\n"
+ + " System.out.println(\"Legacy migration markers: \" +
doneMigrations.size());\n"
+ + "\n"
+ " System.out.println(\"Legacy DB generated at: \" +
workDir.getAbsolutePath());\n"
+ " }\n"
+ " }\n"
@@ -889,6 +972,8 @@ public class LegacyPersistentStorageCompatibilityTest {
return line.startsWith("> Task")
|| line.startsWith("BUILD ")
|| line.contains("Legacy generator")
+ || line.contains("Legacy migrations")
+ || line.contains("Legacy migration markers")
|| line.contains("Legacy WAL stress")
|| line.contains("Legacy Ignite node version")
|| line.contains("Legacy DB generated")
diff --git a/tcbot-engine/build.gradle b/tcbot-engine/build.gradle
index f557ba6c..3606f363 100644
--- a/tcbot-engine/build.gradle
+++ b/tcbot-engine/build.gradle
@@ -26,4 +26,4 @@ dependencies {
testImplementation group: 'junit', name: 'junit', version: junitVer
testImplementation group: 'org.mockito', name: 'mockito-core', version:
mockitoVer
}
-
+
diff --git a/tcbot-github-ignited/build.gradle
b/tcbot-github-ignited/build.gradle
index cdd1ff42..bc131e9b 100644
--- a/tcbot-github-ignited/build.gradle
+++ b/tcbot-github-ignited/build.gradle
@@ -21,4 +21,4 @@ dependencies {
api project(":tcbot-github")
api project(":tcbot-persistence")
}
-
+
diff --git a/tcbot-jira-ignited/build.gradle b/tcbot-jira-ignited/build.gradle
index 5070b4e7..bb41aa53 100644
--- a/tcbot-jira-ignited/build.gradle
+++ b/tcbot-jira-ignited/build.gradle
@@ -21,4 +21,4 @@ dependencies {
api project(":tcbot-jira")
api project(":tcbot-persistence")
}
-
+
diff --git a/tcbot-jira/build.gradle b/tcbot-jira/build.gradle
index ceaedf78..ffafe364 100644
--- a/tcbot-jira/build.gradle
+++ b/tcbot-jira/build.gradle
@@ -21,8 +21,8 @@ dependencies {
api project(":tcbot-common")
// JIRA integration shares entries for pure and Ignited connection, so
persistence module is here for interfaces/annotations
api project(":tcbot-persistence")
-
+
testImplementation group: 'junit', name: 'junit', version: junitVer
testImplementation group: 'org.mockito', name: 'mockito-core', version:
mockitoVer
}
-
+
diff --git a/tcbot-persistence/build.gradle b/tcbot-persistence/build.gradle
index e619aef1..baa488d3 100644
--- a/tcbot-persistence/build.gradle
+++ b/tcbot-persistence/build.gradle
@@ -31,4 +31,4 @@ dependencies {
api "org.apache.ignite:ignite-indexing:$ignVer"
}
-
+
diff --git a/tcbot-teamcity-ignited/build.gradle
b/tcbot-teamcity-ignited/build.gradle
index 1720ef52..6135679d 100644
--- a/tcbot-teamcity-ignited/build.gradle
+++ b/tcbot-teamcity-ignited/build.gradle
@@ -16,7 +16,7 @@
*/
apply plugin: 'java'
-
+
dependencies {
api project(":tcbot-teamcity")
api project(":tcbot-persistence")
@@ -24,4 +24,4 @@ dependencies {
testImplementation group: 'junit', name: 'junit', version: junitVer;
testImplementation group: 'org.mockito', name: 'mockito-core', version:
mockitoVer;
}
-
+
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 771678e6..d4aef425 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
@@ -28,6 +28,7 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -74,6 +75,9 @@ public class BuildRefDao {
/** Update Counters for branch-related changes storage. */
@Inject private UpdateCountersStorage countersStorage;
+ /** Guard for branch history in-memory caches. */
+ private final ReentrantReadWriteLock buildRefsInMemCacheLock = new
ReentrantReadWriteLock(true);
+
/** Non persistence cache for all BuildRefsCompacted for particular branch.
* RunHistKey(ServerId||BranchId||suiteId)-> Build reference
*/
@@ -182,8 +186,15 @@ public class BuildRefDao {
.map(b -> branchNameToHistCacheKey(srvId, b.branch()))
.collect(Collectors.toSet());
- buildRefsInMemCacheForAllBranch.invalidateAll(cacheForAllBranch);
- buildRefsInMemCache.invalidateAll(setOfHistToClear);
+ buildRefsInMemCacheLock.writeLock().lock();
+
+ try {
+ buildRefsInMemCacheForAllBranch.invalidateAll(cacheForAllBranch);
+ buildRefsInMemCache.invalidateAll(setOfHistToClear);
+ }
+ finally {
+ buildRefsInMemCacheLock.writeLock().unlock();
+ }
setOfHistToClear.forEach(b -> {
int branch = b.branch();
@@ -228,22 +239,30 @@ public class BuildRefDao {
branchNameIds.forEach(branchNameId -> {
RunHistKey runHistKey = new RunHistKey(srvId, buildTypeIdId,
branchNameId);
try {
- List<BuildRefCompacted> compactedBuildsForBranch =
- buildRefsInMemCache.get(runHistKey, () -> {
- List<BuildRefCompacted> branch =
getBuildsForBranch(srvId, branchNameId);
+ List<BuildRefCompacted> compactedBuildsForBranch;
+
+ buildRefsInMemCacheLock.readLock().lock();
- List<BuildRefCompacted> resForBranch = branch.stream()
- .filter(e -> e.buildTypeId() == buildTypeIdId)
- .collect(Collectors.toList());
+ try {
+ compactedBuildsForBranch =
buildRefsInMemCache.get(runHistKey, () -> {
+ List<BuildRefCompacted> branch =
getBuildsForBranch(srvId, branchNameId);
- if (!resForBranch.isEmpty()) {
- System.err.println("Branch " +
compactor.getStringFromId(branchNameId)
- + " Suite " +
compactor.getStringFromId(buildTypeIdId)
- + " builds " + resForBranch.size() + " ");
- }
+ List<BuildRefCompacted> resForBranch =
branch.stream()
+ .filter(e -> e.buildTypeId() == buildTypeIdId)
+ .collect(Collectors.toList());
- return resForBranch;
- });
+ if (!resForBranch.isEmpty()) {
+ System.err.println("Branch " +
compactor.getStringFromId(branchNameId)
+ + " Suite " +
compactor.getStringFromId(buildTypeIdId)
+ + " builds " + resForBranch.size() + " ");
+ }
+
+ return resForBranch;
+ });
+ }
+ finally {
+ buildRefsInMemCacheLock.readLock().unlock();
+ }
res.addAll(compactedBuildsForBranch);
}
@@ -289,7 +308,15 @@ public class BuildRefDao {
long branchKey = branchNameToHistCacheKey(srvId, branchNameId);
try {
- return buildRefsInMemCacheForAllBranch.get(branchKey, () ->
getBuildsForBranchNonCached(srvId, branchNameId));
+ buildRefsInMemCacheLock.readLock().lock();
+
+ try {
+ return buildRefsInMemCacheForAllBranch.get(branchKey,
+ () -> getBuildsForBranchNonCached(srvId, branchNameId));
+ }
+ finally {
+ buildRefsInMemCacheLock.readLock().unlock();
+ }
}
catch (ExecutionException e) {
throw ExceptionUtil.propagateException(e);
diff --git a/tcbot-teamcity/build.gradle b/tcbot-teamcity/build.gradle
index 7f18daa5..53211fe1 100644
--- a/tcbot-teamcity/build.gradle
+++ b/tcbot-teamcity/build.gradle
@@ -16,7 +16,7 @@
*/
apply plugin: 'java'
-
+
dependencies {
api project(":tcbot-common")
@@ -25,4 +25,4 @@ dependencies {
api group: 'com.sun.xml.bind', name: 'jaxb-impl', version: jaxbVer
api group: 'com.sun.xml.bind', name: 'jaxb-core', version: '2.3.0'
}
-
+