|
17 | 17 |
|
18 | 18 | package org.apache.ignite.cdc.kafka; |
19 | 19 |
|
20 | | -import java.io.IOException; |
21 | | -import java.nio.file.Files; |
22 | 20 | import java.nio.file.Path; |
23 | 21 | import java.util.ArrayList; |
24 | 22 | import java.util.Collection; |
25 | 23 | import java.util.HashSet; |
26 | 24 | import java.util.Iterator; |
27 | 25 | import java.util.List; |
28 | | -import java.util.Optional; |
29 | 26 | import java.util.Properties; |
30 | 27 | import java.util.Set; |
31 | 28 | import java.util.concurrent.ExecutionException; |
32 | 29 | import java.util.concurrent.Future; |
33 | 30 | import java.util.concurrent.TimeUnit; |
34 | 31 | import java.util.concurrent.TimeoutException; |
35 | 32 | import java.util.function.Function; |
36 | | -import java.util.regex.Pattern; |
37 | | -import java.util.regex.PatternSyntaxException; |
38 | 33 | import java.util.stream.Collectors; |
39 | 34 | import java.util.stream.IntStream; |
40 | 35 |
|
41 | | -import org.apache.ignite.IgniteException; |
42 | 36 | import org.apache.ignite.IgniteLogger; |
43 | 37 | import org.apache.ignite.binary.BinaryType; |
44 | 38 | import org.apache.ignite.cdc.CdcCacheEvent; |
45 | 39 | import org.apache.ignite.cdc.CdcConsumerEx; |
46 | 40 | import org.apache.ignite.cdc.CdcEvent; |
| 41 | +import org.apache.ignite.cdc.CdcRegexManager; |
47 | 42 | import org.apache.ignite.cdc.TypeMapping; |
48 | 43 | import org.apache.ignite.cdc.conflictresolve.CacheVersionConflictResolverImpl; |
49 | 44 | import org.apache.ignite.internal.binary.BinaryTypeImpl; |
|
63 | 58 | import org.apache.kafka.common.serialization.ByteArraySerializer; |
64 | 59 | import org.apache.kafka.common.serialization.IntegerSerializer; |
65 | 60 |
|
66 | | -import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; |
67 | | -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; |
68 | 61 | import static org.apache.ignite.cdc.kafka.KafkaToIgniteCdcStreamerConfiguration.DFLT_KAFKA_REQ_TIMEOUT; |
69 | 62 | import static org.apache.ignite.cdc.kafka.KafkaToIgniteCdcStreamerConfiguration.DFLT_MAX_BATCH_SIZE; |
70 | 63 | import static org.apache.kafka.clients.producer.ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG; |
@@ -158,27 +151,15 @@ public class IgniteToKafkaCdcStreamer implements CdcConsumerEx { |
158 | 151 | /** Cache names. */ |
159 | 152 | private Collection<String> caches; |
160 | 153 |
|
161 | | - /** File with saved names of caches added by cache masks. */ |
162 | | - private static final String SAVED_CACHES_FILE = "caches"; |
163 | | - |
164 | | - /** Temporary file with saved names of caches added by cache masks. */ |
165 | | - private static final String SAVED_CACHES_TMP_FILE = "caches_tmp"; |
166 | | - |
167 | | - /** CDC directory path. */ |
168 | | - private Path cdcDir; |
| 154 | + /** Regexp manager. */ |
| 155 | + private CdcRegexManager regexManager; |
169 | 156 |
|
170 | 157 | /** Include regex templates for cache names. */ |
171 | 158 | private Set<String> includeTemplates = new HashSet<>(); |
172 | 159 |
|
173 | | - /** Compiled include regex patterns for cache names. */ |
174 | | - private Set<Pattern> includeFilters; |
175 | | - |
176 | 160 | /** Exclude regex templates for cache names. */ |
177 | 161 | private Set<String> excludeTemplates = new HashSet<>(); |
178 | 162 |
|
179 | | - /** Compiled exclude regex patterns for cache names. */ |
180 | | - private Set<Pattern> excludeFilters; |
181 | | - |
182 | 163 | /** Max batch size. */ |
183 | 164 | private int maxBatchSz = DFLT_MAX_BATCH_SIZE; |
184 | 165 |
|
@@ -278,42 +259,13 @@ public class IgniteToKafkaCdcStreamer implements CdcConsumerEx { |
278 | 259 | /** {@inheritDoc} */ |
279 | 260 | @Override public void onCacheChange(Iterator<CdcCacheEvent> cacheEvents) { |
280 | 261 | cacheEvents.forEachRemaining(e -> { |
281 | | - matchWithRegexTemplates(e.configuration().getName()); |
| 262 | + matchWithRegex(e.configuration().getName()); |
282 | 263 | }); |
283 | 264 | } |
284 | 265 |
|
285 | 266 | /** {@inheritDoc} */ |
286 | 267 | @Override public void onCacheDestroy(Iterator<Integer> caches) { |
287 | | - caches.forEachRemaining(this::deleteRegexpCacheIfPresent); |
288 | | - } |
289 | | - |
290 | | - /** |
291 | | - * Removes cache added by regexp from cache list, if this cache is present in file, to prevent file size overflow. |
292 | | - * |
293 | | - * @param cacheId Cache id. |
294 | | - */ |
295 | | - private void deleteRegexpCacheIfPresent(Integer cacheId) { |
296 | | - try { |
297 | | - List<String> caches = loadCaches(); |
298 | | - |
299 | | - Optional<String> cacheName = caches.stream() |
300 | | - .filter(name -> CU.cacheId(name) == cacheId) |
301 | | - .findAny(); |
302 | | - |
303 | | - if (cacheName.isPresent()) { |
304 | | - String name = cacheName.get(); |
305 | | - |
306 | | - caches.remove(name); |
307 | | - |
308 | | - save(caches); |
309 | | - |
310 | | - if (log.isInfoEnabled()) |
311 | | - log.info("Cache has been removed from replication [cacheName=" + name + ']'); |
312 | | - } |
313 | | - } |
314 | | - catch (IOException e) { |
315 | | - throw new IgniteException(e); |
316 | | - } |
| 268 | + caches.forEachRemaining(regexManager::deleteRegexpCacheIfPresent); |
317 | 269 | } |
318 | 270 |
|
319 | 271 | /** Send marker(meta need to be updated) record to each partition of events topic. */ |
@@ -393,23 +345,17 @@ private <T> void sendOneBatch( |
393 | 345 | kafkaProps.setProperty(KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName()); |
394 | 346 | kafkaProps.setProperty(VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class.getName()); |
395 | 347 |
|
396 | | - this.cdcDir = cdcDir; |
| 348 | + regexManager = new CdcRegexManager(cdcDir, log); |
397 | 349 |
|
398 | 350 | cachesIds = caches.stream() |
399 | 351 | .map(CU::cacheId) |
400 | 352 | .collect(Collectors.toSet()); |
401 | 353 |
|
402 | | - prepareRegexFilters(); |
| 354 | + regexManager.compileRegexp(includeTemplates, excludeTemplates); |
403 | 355 |
|
404 | | - try { |
405 | | - loadCaches().stream() |
406 | | - .filter(this::matchesFilters) |
| 356 | + regexManager.getSavedCaches().stream() |
407 | 357 | .map(CU::cacheId) |
408 | 358 | .forEach(cachesIds::add); |
409 | | - } |
410 | | - catch (IOException e) { |
411 | | - throw new IgniteException(e); |
412 | | - } |
413 | 359 |
|
414 | 360 | try { |
415 | 361 | producer = new KafkaProducer<>(kafkaProps); |
@@ -457,108 +403,16 @@ public IgniteToKafkaCdcStreamer setOnlyPrimary(boolean onlyPrimary) { |
457 | 403 | } |
458 | 404 |
|
459 | 405 | /** |
460 | | - * Compiles regex patterns from user templates. |
461 | | - * |
462 | | - * @throws PatternSyntaxException If the template's syntax is invalid |
463 | | - */ |
464 | | - private void prepareRegexFilters() { |
465 | | - includeFilters = includeTemplates.stream() |
466 | | - .map(Pattern::compile) |
467 | | - .collect(Collectors.toSet()); |
468 | | - |
469 | | - excludeFilters = excludeTemplates.stream() |
470 | | - .map(Pattern::compile) |
471 | | - .collect(Collectors.toSet()); |
472 | | - } |
473 | | - |
474 | | - /** |
475 | | - * Loads saved caches from file. |
476 | | - * |
477 | | - * @return List of saved caches names. |
478 | | - */ |
479 | | - private List<String> loadCaches() throws IOException { |
480 | | - if (cdcDir == null) { |
481 | | - throw new IgniteException("Can't load '" + SAVED_CACHES_FILE + "' file. Cdc directory is null"); |
482 | | - } |
483 | | - Path savedCachesPath = cdcDir.resolve(SAVED_CACHES_FILE); |
484 | | - |
485 | | - if (Files.notExists(savedCachesPath)) { |
486 | | - Files.createFile(savedCachesPath); |
487 | | - |
488 | | - if (log.isInfoEnabled()) |
489 | | - log.info("Cache list created: " + savedCachesPath); |
490 | | - } |
491 | | - |
492 | | - return Files.readAllLines(savedCachesPath); |
493 | | - } |
494 | | - |
495 | | - /** |
496 | | - * Matches cache name with compiled regex patterns. |
| 406 | + * Finds a match between the cache name and user regex templates. |
| 407 | + * If a match is found, adds the cache to replication. |
497 | 408 | * |
498 | 409 | * @param cacheName Cache name. |
499 | | - * @return True if cache name match include patterns and don't match exclude patterns. |
500 | 410 | */ |
501 | | - private boolean matchesFilters(String cacheName) { |
502 | | - boolean matchesInclude = includeFilters.stream() |
503 | | - .anyMatch(pattern -> pattern.matcher(cacheName).matches()); |
504 | | - |
505 | | - boolean notMatchesExclude = excludeFilters.stream() |
506 | | - .noneMatch(pattern -> pattern.matcher(cacheName).matches()); |
507 | | - |
508 | | - return matchesInclude && notMatchesExclude; |
509 | | - } |
510 | | - |
511 | | - /** |
512 | | - * Finds match between cache name and user's regex templates. |
513 | | - * If match is found, adds this cache's id to id's list and saves cache name to file. |
514 | | - * |
515 | | - * @param cacheName Cache name. |
516 | | - */ |
517 | | - private void matchWithRegexTemplates(String cacheName) { |
| 411 | + private void matchWithRegex(String cacheName) { |
518 | 412 | int cacheId = CU.cacheId(cacheName); |
519 | 413 |
|
520 | | - if (!cachesIds.contains(cacheId) && matchesFilters(cacheName)) { |
| 414 | + if (!cachesIds.contains(cacheId) && regexManager.match(cacheName)) |
521 | 415 | cachesIds.add(cacheId); |
522 | | - |
523 | | - try { |
524 | | - List<String> caches = loadCaches(); |
525 | | - |
526 | | - caches.add(cacheName); |
527 | | - |
528 | | - save(caches); |
529 | | - } |
530 | | - catch (IOException e) { |
531 | | - throw new IgniteException(e); |
532 | | - } |
533 | | - |
534 | | - if (log.isInfoEnabled()) |
535 | | - log.info("Cache has been added to replication [cacheName=" + cacheName + "]"); |
536 | | - } |
537 | | - } |
538 | | - |
539 | | - /** |
540 | | - * Writes caches list to file |
541 | | - * |
542 | | - * @param caches Caches list. |
543 | | - */ |
544 | | - private void save(List<String> caches) throws IOException { |
545 | | - if (cdcDir == null) { |
546 | | - throw new IgniteException("Can't write to '" + SAVED_CACHES_FILE + "' file. Cdc directory is null"); |
547 | | - } |
548 | | - Path savedCachesPath = cdcDir.resolve(SAVED_CACHES_FILE); |
549 | | - Path tmpSavedCachesPath = cdcDir.resolve(SAVED_CACHES_TMP_FILE); |
550 | | - |
551 | | - StringBuilder cacheList = new StringBuilder(); |
552 | | - |
553 | | - for (String cache : caches) { |
554 | | - cacheList.append(cache); |
555 | | - |
556 | | - cacheList.append('\n'); |
557 | | - } |
558 | | - |
559 | | - Files.write(tmpSavedCachesPath, cacheList.toString().getBytes()); |
560 | | - |
561 | | - Files.move(tmpSavedCachesPath, savedCachesPath, ATOMIC_MOVE, REPLACE_EXISTING); |
562 | 416 | } |
563 | 417 |
|
564 | 418 | /** |
|
0 commit comments