2929import java .nio .file .Files ;
3030import java .nio .file .Path ;
3131import java .util .HashMap ;
32+ import java .util .HashSet ;
3233import java .util .List ;
3334import java .util .Map ;
35+ import java .util .Objects ;
36+ import java .util .Set ;
37+ import java .util .function .Consumer ;
3438import org .apache .ignite .internal .catalog .storage .serialization .CatalogEntrySerializerProvider ;
3539import org .apache .ignite .internal .catalog .storage .serialization .CatalogObjectSerializer ;
40+ import org .apache .ignite .internal .catalog .storage .serialization .CatalogSerializer ;
3641import org .apache .ignite .internal .catalog .storage .serialization .MarshallableEntry ;
3742import org .apache .ignite .internal .catalog .storage .serialization .MarshallableEntryType ;
3843import org .apache .ignite .internal .catalog .storage .serialization .UpdateLogMarshaller ;
3944import org .apache .ignite .internal .catalog .storage .serialization .UpdateLogMarshallerImpl ;
4045import org .apache .ignite .internal .logger .IgniteLogger ;
4146import org .assertj .core .api .BDDAssertions ;
47+ import org .jetbrains .annotations .Nullable ;
4248
4349final class CatalogSerializationChecker {
4450
4551 private static final String UPDATE_TIMESTAMP_FIELD_REGEX = ".*updateTimestamp" ;
4652
53+ private static final String V1_SERDE_NOTE = "MANUAL CALL TO SUPPORT V1 SERIALIZATION" ;
54+
4755 private final Map <Integer , Integer > expectedEntryVersions = new HashMap <>();
4856
4957 private boolean writeSnapshot ;
@@ -52,24 +60,32 @@ final class CatalogSerializationChecker {
5260
5361 private final String directory ;
5462
55- private final int entryVersion ;
63+ private final int defaultEntryVersion ;
5664
5765 private final boolean expectExactProtocolVersion ;
5866
5967 private final int protocolVersion ;
6068
69+ private final Set <SerializerClass > collectedSerializers = new HashSet <>();
70+
71+ private final Consumer <SerializerClass > recordSerializer ;
72+
73+ private boolean addSerializerManually ;
74+
6175 CatalogSerializationChecker (
6276 IgniteLogger log ,
6377 String directory ,
64- int entryVersion ,
78+ int defaultEntryVersion ,
6579 boolean expectExactProtocolVersion ,
66- int protocolVersion
80+ int protocolVersion ,
81+ Consumer <SerializerClass > recordSerializer
6782 ) {
6883 this .log = log ;
6984 this .directory = directory ;
70- this .entryVersion = entryVersion ;
85+ this .defaultEntryVersion = defaultEntryVersion ;
7186 this .expectExactProtocolVersion = expectExactProtocolVersion ;
7287 this .protocolVersion = protocolVersion ;
88+ this .recordSerializer = recordSerializer ;
7389 }
7490
7591 void writeSnapshot (boolean value ) {
@@ -80,6 +96,10 @@ void addExpectedVersion(int typeId, int entryVersion) {
8096 expectedEntryVersions .put (typeId , entryVersion );
8197 }
8298
99+ void addClassesManually (boolean value ) {
100+ addSerializerManually = value ;
101+ }
102+
83103 void reset () {
84104 expectedEntryVersions .clear ();
85105 writeSnapshot = false ;
@@ -96,7 +116,7 @@ void compareSnapshotEntry(SnapshotEntry expectedEntry, String fileName, int vers
96116 var assertion = BDDAssertions .assertThat (expectedEntry .snapshot ())
97117 .usingRecursiveComparison ();
98118
99- if (entryVersion == 1 ) {
119+ if (defaultEntryVersion == 1 ) {
100120 // Ignoring update timestamp for version 1.
101121 assertion = assertion .ignoringFieldsMatchingRegexes (UPDATE_TIMESTAMP_FIELD_REGEX );
102122 }
@@ -112,20 +132,42 @@ void compareEntries(List<UpdateEntry> entries, String fileName, int version) {
112132 UpdateEntry expectedEntry = entries .get (i );
113133 UpdateEntry actualEntry = actual .get (i );
114134
115- var assertion = BDDAssertions .assertThat (actualEntry ). as ( "entry#" + i )
116- .usingRecursiveComparison ();
135+ var assertion = BDDAssertions .assertThat (actualEntry )
136+ .as ( "entry#" + i ). usingRecursiveComparison ();
117137
118- if (entryVersion == 1 ) {
138+ if (defaultEntryVersion == 1 ) {
119139 // Ignoring update timestamp for version 1.
120140 assertion = assertion .ignoringFieldsMatchingRegexes (UPDATE_TIMESTAMP_FIELD_REGEX );
121141 }
122142
143+ if (addSerializerManually ) {
144+ // Record entry version to support v1 serialization.
145+ // This is not needed by v2 serialization.
146+ recordSerializer (expectedEntry .typeId (), version , V1_SERDE_NOTE );
147+ }
148+
123149 assertion .isEqualTo (expectedEntry );
124150 }
125151 }
126152
153+ private void recordSerializer (int typeId , int version , @ Nullable String note ) {
154+ SerializerClass sc = new SerializerClass (typeId , version );
155+ if (!collectedSerializers .add (sc )) {
156+ return ;
157+ }
158+ recordSerializer .accept (sc );
159+
160+ MarshallableEntryType entryType = getMarshallableEntryType (typeId );
161+ if (note != null ) {
162+ log .info ("{} uses version: {}, NOTE: {}" , entryType , version , note );
163+ } else {
164+ log .info ("{} uses version: {}" , entryType , version );
165+ }
166+ }
167+
127168 @ SuppressWarnings ({"unchecked" , "rawtypes" })
128169 private <T extends UpdateEntry > List <T > checkEntries (List <? extends T > entries , String fileName , int version ) {
170+ // The version number is ignored, checkEntry uses the concrete serializer version.
129171 VersionedUpdate update = new VersionedUpdate (1 , 100L , (List <UpdateEntry >) entries );
130172 VersionedUpdate deserializedUpdate = checkEntry (VersionedUpdate .class , fileName , version , update );
131173
@@ -151,7 +193,8 @@ private <T extends UpdateLogEvent> T checkEntry(Class<T> entryClass, String entr
151193
152194 log .info ("Read fileName: {}, class: {}, entryVersion: {}" , fileName , entryClass .getSimpleName (), entryVersion );
153195
154- UpdateLogMarshaller marshaller = new UpdateLogMarshallerImpl (provider , protocolVersion );
196+ SerializerVersionCollectingProvider versionCollectingProvider = new SerializerVersionCollectingProvider (provider );
197+ UpdateLogMarshaller marshaller = new UpdateLogMarshallerImpl (versionCollectingProvider , protocolVersion );
155198
156199 if (writeSnapshot ) {
157200 writeEntry (entry , Path .of ("src" , "test" , "resources" , directory , fileName ), marshaller );
@@ -183,11 +226,36 @@ private void writeEntry(UpdateLogEvent entry, Path resourcePath, UpdateLogMarsha
183226 }
184227 }
185228
186- private static class VersionCheckingProvider implements CatalogEntrySerializerProvider {
229+ private final class SerializerVersionCollectingProvider implements CatalogEntrySerializerProvider {
230+
231+ private final CatalogEntrySerializerProvider delegate ;
232+
233+ private SerializerVersionCollectingProvider (CatalogEntrySerializerProvider delegate ) {
234+ this .delegate = delegate ;
235+ }
236+
237+ @ Override
238+ public <T extends MarshallableEntry > CatalogObjectSerializer <T > get (int version , int typeId ) {
239+ recordSerializer (typeId , version , null );
240+
241+ return delegate .get (version , typeId );
242+ }
243+
244+ @ Override
245+ public int latestSerializerVersion (int typeId ) {
246+ int version = delegate .latestSerializerVersion (typeId );
247+
248+ recordSerializer (typeId , version , null );
249+
250+ return version ;
251+ }
252+ }
253+
254+ private static final class VersionCheckingProvider implements CatalogEntrySerializerProvider {
187255
188256 private final CatalogEntrySerializerProvider provider ;
189257
190- private final int protocolVersion ;
258+ private final int expectedProtocolVersion ;
191259
192260 private final Map <Integer , Integer > entryVersions = new HashMap <>();
193261
@@ -197,7 +265,7 @@ private VersionCheckingProvider(
197265 Map <Integer , Integer > entryVersions
198266 ) {
199267 this .provider = provider ;
200- this .protocolVersion = expectedProtocolVersion ;
268+ this .expectedProtocolVersion = expectedProtocolVersion ;
201269 this .entryVersions .putAll (entryVersions );
202270 }
203271
@@ -219,7 +287,7 @@ public int latestSerializerVersion(int typeId) {
219287 }
220288
221289 private void checkVersion (int typeId , int entryVersion ) {
222- int expectedEntryVersion = entryVersions .getOrDefault (typeId , protocolVersion );
290+ int expectedEntryVersion = entryVersions .getOrDefault (typeId , expectedProtocolVersion );
223291 if (entryVersion != expectedEntryVersion ) {
224292 MarshallableEntryType type = null ;
225293
@@ -238,4 +306,70 @@ private void checkVersion(int typeId, int entryVersion) {
238306 }
239307 }
240308 }
309+
310+ static Set <SerializerClass > findEntrySerializers () {
311+ Set <SerializerClass > classes = new HashSet <>();
312+
313+ for (var entryType : MarshallableEntryType .values ()) {
314+ for (Class <?> declaredClass : entryType .container ().getDeclaredClasses ()) {
315+ if (CatalogObjectSerializer .class .isAssignableFrom (declaredClass )) {
316+ CatalogSerializer catalogSerializer = declaredClass .getAnnotation (CatalogSerializer .class );
317+
318+ classes .add (new SerializerClass (entryType .id (), catalogSerializer .version ()));
319+ }
320+ }
321+ }
322+
323+ return classes ;
324+ }
325+
326+ protected static final class SerializerClass implements Comparable <SerializerClass > {
327+ final int entryTypeId ;
328+ final int serializerVersion ;
329+
330+ SerializerClass (int entryTypeId , int serializerVersion ) {
331+ this .entryTypeId = entryTypeId ;
332+ this .serializerVersion = serializerVersion ;
333+ }
334+
335+ @ Override
336+ public String toString () {
337+ MarshallableEntryType entryType = getMarshallableEntryType (entryTypeId );
338+ return "SerializerClass{" + entryType + "#" + serializerVersion + "}" ;
339+ }
340+
341+ @ Override
342+ public boolean equals (Object o ) {
343+ if (o == null || getClass () != o .getClass ()) {
344+ return false ;
345+ }
346+ SerializerClass that = (SerializerClass ) o ;
347+ return serializerVersion == that .serializerVersion && entryTypeId == that .entryTypeId ;
348+ }
349+
350+ @ Override
351+ public int hashCode () {
352+ return Objects .hash (entryTypeId , serializerVersion );
353+ }
354+
355+ @ Override
356+ public int compareTo (CatalogSerializationChecker .SerializerClass o ) {
357+ int c1 = Integer .compare (entryTypeId , o .entryTypeId );
358+ if (c1 != 0 ) {
359+ return c1 ;
360+ } else {
361+ return Integer .compare (serializerVersion , o .serializerVersion );
362+ }
363+ }
364+ }
365+
366+ private static MarshallableEntryType getMarshallableEntryType (int typeId ) {
367+ for (MarshallableEntryType t : MarshallableEntryType .values ()) {
368+ if (t .id () == typeId ) {
369+ return t ;
370+ }
371+ }
372+
373+ throw new IllegalArgumentException ("Unexpected type: " + typeId );
374+ }
241375}
0 commit comments