2323import java .util .LinkedHashSet ;
2424import java .util .List ;
2525import java .util .Set ;
26+ import java .util .concurrent .CompletionStage ;
2627import java .util .function .IntFunction ;
2728import java .util .stream .Collectors ;
2829import java .util .stream .Stream ;
5758
5859import com .datastax .oss .driver .api .core .CqlSession ;
5960import com .datastax .oss .driver .api .core .CqlSessionBuilder ;
61+ import com .datastax .oss .driver .internal .core .util .concurrent .CompletableFutures ;
6062
6163/**
6264 * Factory for creating and configuring a Cassandra {@link CqlSession}, which is a thread-safe singleton. As such, it is
@@ -108,6 +110,8 @@ public class CqlSessionFactoryBean
108110
109111 private SchemaAction schemaAction = SchemaAction .NONE ;
110112
113+ private boolean suspendLifecycleSchemaRefresh = false ;
114+
111115 private @ Nullable SessionBuilderConfigurer sessionBuilderConfigurer ;
112116
113117 private IntFunction <Collection <InetSocketAddress >> contactPoints = port -> createInetSocketAddresses (
@@ -348,8 +352,8 @@ protected CassandraMappingContext getMappingContext() {
348352 * Set the {@link SchemaAction}.
349353 *
350354 * @param schemaAction must not be {@literal null}.
351- * @deprecated Use {@link CassandraSessionFactoryBean } with
352- * {@link CassandraSessionFactoryBean #setSchemaAction(SchemaAction)} instead.
355+ * @deprecated Use {@link SessionFactoryFactoryBean } with
356+ * {@link SessionFactoryFactoryBean #setSchemaAction(SchemaAction)} instead.
353357 */
354358 @ Deprecated
355359 public void setSchemaAction (SchemaAction schemaAction ) {
@@ -366,6 +370,24 @@ public SchemaAction getSchemaAction() {
366370 return this .schemaAction ;
367371 }
368372
373+ /**
374+ * Set whether to suspend schema refresh settings during {@link #afterPropertiesSet()} and {@link #destroy()}
375+ * lifecycle callbacks. Disabled by default to use schema metadata settings of the session configuration. When enabled
376+ * (set to {@code true}), then schema refresh during lifecycle methods is suspended until finishing schema actions to
377+ * avoid periodic schema refreshes for each DDL statement.
378+ * <p>
379+ * Suspending schema refresh can be useful to delay schema agreement until the entire schema is created. Note that
380+ * disabling schema refresh may interfere with schema actions. {@link SchemaAction#RECREATE_DROP_UNUSED} and
381+ * mapping-based schema creation rely on schema metadata.
382+ *
383+ * @param suspendLifecycleSchemaRefresh {@code true} to suspend the schema refresh during lifecycle callbacks;
384+ * {@code false} otherwise to retain the session schema refresh configuration.
385+ * @since 2.7
386+ */
387+ public void setSuspendLifecycleSchemaRefresh (boolean suspendLifecycleSchemaRefresh ) {
388+ this .suspendLifecycleSchemaRefresh = suspendLifecycleSchemaRefresh ;
389+ }
390+
369391 /**
370392 * Returns a reference to the connected Cassandra {@link CqlSession}.
371393 *
@@ -451,20 +473,30 @@ public void afterPropertiesSet() {
451473
452474 this .session = buildSession (sessionBuilder );
453475
454- try {
455- SchemaRefreshUtils .withDisabledSchema (this .session , () -> {
456- executeCql (getStartupScripts ().stream (), this .session );
457- performSchemaAction ();
458- });
459- } catch (RuntimeException e ) {
460- throw e ;
461- } catch (Exception e ) {
462- throw new IllegalStateException ("Unexpected checked exception thrown" , e );
476+ initializeSchema (this .systemSession , this .session );
477+ }
478+
479+ private void initializeSchema (CqlSession systemSession , CqlSession session ) {
480+
481+ Runnable schemaActionRunnable = () -> {
482+
483+ executeCql (getStartupScripts ().stream (), session );
484+ performSchemaAction ();
485+ };
486+
487+ List <CompletionStage <?>> futures = new ArrayList <>(2 );
488+
489+ if (this .suspendLifecycleSchemaRefresh ) {
490+ futures .add (SchemaUtils .withSuspendedAsyncSchemaRefresh (session , schemaActionRunnable ));
491+ } else {
492+ futures .add (SchemaUtils .withAsyncSchemaRefresh (session , schemaActionRunnable ));
463493 }
464494
465- if (this . systemSession .isSchemaMetadataEnabled ()) {
466- this . systemSession .refreshSchema ( );
495+ if (systemSession .isSchemaMetadataEnabled ()) {
496+ futures . add ( systemSession .refreshSchemaAsync () );
467497 }
498+
499+ futures .forEach (CompletableFutures ::getUninterruptibly );
468500 }
469501
470502 protected CqlSessionBuilder buildBuilder () {
@@ -532,7 +564,15 @@ private void initializeCluster(CqlSession session) {
532564 keyspaceStartupSpecifications .addAll (this .keyspaceCreations );
533565 keyspaceStartupSpecifications .addAll (this .keyspaceAlterations );
534566
535- executeSpecificationsAndScripts (keyspaceStartupSpecifications , this .keyspaceStartupScripts , session );
567+ Runnable schemaActionRunnable = () -> {
568+ executeSpecificationsAndScripts (keyspaceStartupSpecifications , this .keyspaceStartupScripts , session );
569+ };
570+
571+ if (this .suspendLifecycleSchemaRefresh ) {
572+ SchemaUtils .withSuspendedAsyncSchemaRefresh (session , schemaActionRunnable );
573+ } else {
574+ schemaActionRunnable .run ();
575+ }
536576 }
537577
538578 /**
@@ -560,7 +600,7 @@ private void generateSpecifications(Collection<KeyspaceActionSpecification> spec
560600 }
561601
562602 /**
563- * Perform the configure {@link SchemaAction} using {@link CassandraMappingContext} metadata.
603+ * Perform the configured {@link SchemaAction} using {@link CassandraMappingContext} metadata.
564604 */
565605 protected void performSchemaAction () {
566606
@@ -644,8 +684,23 @@ public DataAccessException translateExceptionIfPossible(RuntimeException e) {
644684 public void destroy () {
645685
646686 if (this .session != null ) {
647- executeCql (getShutdownScripts ().stream (), this .session );
648- executeSpecificationsAndScripts (this .keyspaceDrops , this .keyspaceShutdownScripts , this .systemSession );
687+
688+ Runnable schemaActionRunnable = () -> {
689+ executeCql (getShutdownScripts ().stream (), this .session );
690+ };
691+
692+ Runnable systemSchemaActionRunnable = () -> {
693+ executeSpecificationsAndScripts (this .keyspaceDrops , this .keyspaceShutdownScripts , this .systemSession );
694+ };
695+
696+ if (this .suspendLifecycleSchemaRefresh ) {
697+ SchemaUtils .withSuspendedAsyncSchemaRefresh (this .session , schemaActionRunnable );
698+ SchemaUtils .withSuspendedAsyncSchemaRefresh (this .systemSession , systemSchemaActionRunnable );
699+ } else {
700+ schemaActionRunnable .run ();
701+ systemSchemaActionRunnable .run ();
702+ }
703+
649704 closeSession ();
650705 closeSystemSession ();
651706 }
0 commit comments