@@ -633,9 +633,14 @@ public boolean isClosed() {
633
633
}
634
634
635
635
private static void checkNotClosed (Manager manager ) {
636
- if (manager .isClosed ())
636
+ if (manager .errorDuringInit ()) {
637
+ throw new IllegalStateException (
638
+ "Can't use this cluster instance because it encountered an error in its initialization" ,
639
+ manager .getInitException ());
640
+ } else if (manager .isClosed ()) {
637
641
throw new IllegalStateException (
638
642
"Can't use this cluster instance because it was previously closed" );
643
+ }
639
644
}
640
645
641
646
/**
@@ -1385,9 +1390,9 @@ private static String generateClusterName() {
1385
1390
class Manager implements Connection .DefaultResponseHandler {
1386
1391
1387
1392
final String clusterName ;
1388
- private boolean isInit ;
1393
+ private volatile boolean isInit ;
1389
1394
private volatile boolean isFullyInit ;
1390
-
1395
+ private Exception initException ;
1391
1396
// Initial contacts point
1392
1397
final List <InetSocketAddress > contactPoints ;
1393
1398
final Set <SessionManager > sessions = new CopyOnWriteArraySet <SessionManager >();
@@ -1448,119 +1453,121 @@ private Manager(
1448
1453
// on it so synchronized is good enough.
1449
1454
synchronized void init () {
1450
1455
checkNotClosed (this );
1451
- if (isInit ) return ;
1456
+ if (isInit ) {
1457
+ return ;
1458
+ }
1452
1459
isInit = true ;
1460
+ try {
1461
+ logger .debug ("Starting new cluster with contact points " + contactPoints );
1462
+
1463
+ this .configuration .register (this );
1464
+
1465
+ ThreadingOptions threadingOptions = this .configuration .getThreadingOptions ();
1466
+
1467
+ // executor
1468
+ ExecutorService tmpExecutor = threadingOptions .createExecutor (clusterName );
1469
+ this .executorQueue =
1470
+ (tmpExecutor instanceof ThreadPoolExecutor )
1471
+ ? ((ThreadPoolExecutor ) tmpExecutor ).getQueue ()
1472
+ : null ;
1473
+ this .executor = MoreExecutors .listeningDecorator (tmpExecutor );
1474
+
1475
+ // blocking executor
1476
+ ExecutorService tmpBlockingExecutor = threadingOptions .createBlockingExecutor (clusterName );
1477
+ this .blockingExecutorQueue =
1478
+ (tmpBlockingExecutor instanceof ThreadPoolExecutor )
1479
+ ? ((ThreadPoolExecutor ) tmpBlockingExecutor ).getQueue ()
1480
+ : null ;
1481
+ this .blockingExecutor = MoreExecutors .listeningDecorator (tmpBlockingExecutor );
1482
+
1483
+ // reconnection executor
1484
+ this .reconnectionExecutor = threadingOptions .createReconnectionExecutor (clusterName );
1485
+ this .reconnectionExecutorQueue =
1486
+ (reconnectionExecutor instanceof ThreadPoolExecutor )
1487
+ ? ((ThreadPoolExecutor ) reconnectionExecutor ).getQueue ()
1488
+ : null ;
1489
+
1490
+ // scheduled tasks executor
1491
+ this .scheduledTasksExecutor = threadingOptions .createScheduledTasksExecutor (clusterName );
1492
+ this .scheduledTasksExecutorQueue =
1493
+ (scheduledTasksExecutor instanceof ThreadPoolExecutor )
1494
+ ? ((ThreadPoolExecutor ) scheduledTasksExecutor ).getQueue ()
1495
+ : null ;
1496
+
1497
+ this .reaper = new ConnectionReaper (threadingOptions .createReaperExecutor (clusterName ));
1498
+ this .metadata = new Metadata (this );
1499
+ this .connectionFactory = new Connection .Factory (this , configuration );
1500
+ this .controlConnection = new ControlConnection (this );
1501
+ this .metrics = configuration .getMetricsOptions ().isEnabled () ? new Metrics (this ) : null ;
1502
+ this .preparedQueries = new MapMaker ().weakValues ().makeMap ();
1503
+
1504
+ // create debouncers - at this stage, they are not running yet
1505
+ final QueryOptions queryOptions = configuration .getQueryOptions ();
1506
+ this .nodeListRefreshRequestDebouncer =
1507
+ new EventDebouncer <NodeListRefreshRequest >(
1508
+ "Node list refresh" ,
1509
+ scheduledTasksExecutor ,
1510
+ new NodeListRefreshRequestDeliveryCallback ()) {
1453
1511
1454
- logger .debug ("Starting new cluster with contact points " + contactPoints );
1455
-
1456
- this .configuration .register (this );
1457
-
1458
- ThreadingOptions threadingOptions = this .configuration .getThreadingOptions ();
1459
-
1460
- // executor
1461
- ExecutorService tmpExecutor = threadingOptions .createExecutor (clusterName );
1462
- this .executorQueue =
1463
- (tmpExecutor instanceof ThreadPoolExecutor )
1464
- ? ((ThreadPoolExecutor ) tmpExecutor ).getQueue ()
1465
- : null ;
1466
- this .executor = MoreExecutors .listeningDecorator (tmpExecutor );
1467
-
1468
- // blocking executor
1469
- ExecutorService tmpBlockingExecutor = threadingOptions .createBlockingExecutor (clusterName );
1470
- this .blockingExecutorQueue =
1471
- (tmpBlockingExecutor instanceof ThreadPoolExecutor )
1472
- ? ((ThreadPoolExecutor ) tmpBlockingExecutor ).getQueue ()
1473
- : null ;
1474
- this .blockingExecutor = MoreExecutors .listeningDecorator (tmpBlockingExecutor );
1475
-
1476
- // reconnection executor
1477
- this .reconnectionExecutor = threadingOptions .createReconnectionExecutor (clusterName );
1478
- this .reconnectionExecutorQueue =
1479
- (reconnectionExecutor instanceof ThreadPoolExecutor )
1480
- ? ((ThreadPoolExecutor ) reconnectionExecutor ).getQueue ()
1481
- : null ;
1482
-
1483
- // scheduled tasks executor
1484
- this .scheduledTasksExecutor = threadingOptions .createScheduledTasksExecutor (clusterName );
1485
- this .scheduledTasksExecutorQueue =
1486
- (scheduledTasksExecutor instanceof ThreadPoolExecutor )
1487
- ? ((ThreadPoolExecutor ) scheduledTasksExecutor ).getQueue ()
1488
- : null ;
1489
-
1490
- this .reaper = new ConnectionReaper (threadingOptions .createReaperExecutor (clusterName ));
1491
- this .metadata = new Metadata (this );
1492
- this .connectionFactory = new Connection .Factory (this , configuration );
1493
- this .controlConnection = new ControlConnection (this );
1494
- this .metrics = configuration .getMetricsOptions ().isEnabled () ? new Metrics (this ) : null ;
1495
- this .preparedQueries = new MapMaker ().weakValues ().makeMap ();
1496
-
1497
- // create debouncers - at this stage, they are not running yet
1498
- final QueryOptions queryOptions = configuration .getQueryOptions ();
1499
- this .nodeListRefreshRequestDebouncer =
1500
- new EventDebouncer <NodeListRefreshRequest >(
1501
- "Node list refresh" ,
1502
- scheduledTasksExecutor ,
1503
- new NodeListRefreshRequestDeliveryCallback ()) {
1504
-
1505
- @ Override
1506
- int maxPendingEvents () {
1507
- return configuration .getQueryOptions ().getMaxPendingRefreshNodeListRequests ();
1508
- }
1512
+ @ Override
1513
+ int maxPendingEvents () {
1514
+ return configuration .getQueryOptions ().getMaxPendingRefreshNodeListRequests ();
1515
+ }
1509
1516
1510
- @ Override
1511
- long delayMs () {
1512
- return configuration .getQueryOptions ().getRefreshNodeListIntervalMillis ();
1513
- }
1514
- };
1515
- this .nodeRefreshRequestDebouncer =
1516
- new EventDebouncer <NodeRefreshRequest >(
1517
- "Node refresh" , scheduledTasksExecutor , new NodeRefreshRequestDeliveryCallback ()) {
1517
+ @ Override
1518
+ long delayMs () {
1519
+ return configuration .getQueryOptions ().getRefreshNodeListIntervalMillis ();
1520
+ }
1521
+ };
1522
+ this .nodeRefreshRequestDebouncer =
1523
+ new EventDebouncer <NodeRefreshRequest >(
1524
+ "Node refresh" , scheduledTasksExecutor , new NodeRefreshRequestDeliveryCallback ()) {
1518
1525
1519
- @ Override
1520
- int maxPendingEvents () {
1521
- return configuration .getQueryOptions ().getMaxPendingRefreshNodeRequests ();
1522
- }
1526
+ @ Override
1527
+ int maxPendingEvents () {
1528
+ return configuration .getQueryOptions ().getMaxPendingRefreshNodeRequests ();
1529
+ }
1523
1530
1524
- @ Override
1525
- long delayMs () {
1526
- return configuration .getQueryOptions ().getRefreshNodeIntervalMillis ();
1527
- }
1528
- };
1529
- this .schemaRefreshRequestDebouncer =
1530
- new EventDebouncer <SchemaRefreshRequest >(
1531
- "Schema refresh" ,
1532
- scheduledTasksExecutor ,
1533
- new SchemaRefreshRequestDeliveryCallback ()) {
1531
+ @ Override
1532
+ long delayMs () {
1533
+ return configuration .getQueryOptions ().getRefreshNodeIntervalMillis ();
1534
+ }
1535
+ };
1536
+ this .schemaRefreshRequestDebouncer =
1537
+ new EventDebouncer <SchemaRefreshRequest >(
1538
+ "Schema refresh" ,
1539
+ scheduledTasksExecutor ,
1540
+ new SchemaRefreshRequestDeliveryCallback ()) {
1534
1541
1535
- @ Override
1536
- int maxPendingEvents () {
1537
- return configuration .getQueryOptions ().getMaxPendingRefreshSchemaRequests ();
1538
- }
1542
+ @ Override
1543
+ int maxPendingEvents () {
1544
+ return configuration .getQueryOptions ().getMaxPendingRefreshSchemaRequests ();
1545
+ }
1539
1546
1540
- @ Override
1541
- long delayMs () {
1542
- return configuration .getQueryOptions ().getRefreshSchemaIntervalMillis ();
1543
- }
1544
- };
1547
+ @ Override
1548
+ long delayMs () {
1549
+ return configuration .getQueryOptions ().getRefreshSchemaIntervalMillis ();
1550
+ }
1551
+ };
1545
1552
1546
- this .scheduledTasksExecutor .scheduleWithFixedDelay (
1547
- new CleanupIdleConnectionsTask (), 10 , 10 , TimeUnit .SECONDS );
1553
+ this .scheduledTasksExecutor .scheduleWithFixedDelay (
1554
+ new CleanupIdleConnectionsTask (), 10 , 10 , TimeUnit .SECONDS );
1548
1555
1549
- for (InetSocketAddress address : contactPoints ) {
1550
- // We don't want to signal -- call onAdd() -- because nothing is ready
1551
- // yet (loadbalancing policy, control connection, ...). All we want is
1552
- // create the Host object so we can initialize the control connection.
1553
- metadata .addIfAbsent (metadata .newHost (address ));
1554
- }
1556
+ for (InetSocketAddress address : contactPoints ) {
1557
+ // We don't want to signal -- call onAdd() -- because nothing is ready
1558
+ // yet (loadbalancing policy, control connection, ...). All we want is
1559
+ // create the Host object so we can initialize the control connection.
1560
+ metadata .addIfAbsent (metadata .newHost (address ));
1561
+ }
1555
1562
1556
- Collection <Host > allHosts = metadata .allHosts ();
1563
+ Collection <Host > allHosts = metadata .allHosts ();
1557
1564
1558
- // At this stage, metadata.allHosts() only contains the contact points, that's what we want to
1559
- // pass to LBP.init().
1560
- // But the control connection will initialize first and discover more hosts, so make a copy.
1561
- Set <Host > contactPointHosts = Sets .newHashSet (allHosts );
1565
+ // At this stage, metadata.allHosts() only contains the contact points, that's what we want
1566
+ // to
1567
+ // pass to LBP.init().
1568
+ // But the control connection will initialize first and discover more hosts, so make a copy.
1569
+ Set <Host > contactPointHosts = Sets .newHashSet (allHosts );
1562
1570
1563
- try {
1564
1571
negotiateProtocolVersionAndConnect ();
1565
1572
1566
1573
// The control connection can mark hosts down if it failed to connect to them, or remove
@@ -1631,7 +1638,8 @@ long delayMs() {
1631
1638
this .nodeRefreshRequestDebouncer .start ();
1632
1639
1633
1640
isFullyInit = true ;
1634
- } catch (NoHostAvailableException e ) {
1641
+ } catch (RuntimeException e ) {
1642
+ initException = e ;
1635
1643
close ();
1636
1644
throw e ;
1637
1645
}
@@ -1717,6 +1725,14 @@ boolean isClosed() {
1717
1725
return closeFuture .get () != null ;
1718
1726
}
1719
1727
1728
+ boolean errorDuringInit () {
1729
+ return (isInit && initException != null );
1730
+ }
1731
+
1732
+ Exception getInitException () {
1733
+ return initException ;
1734
+ }
1735
+
1720
1736
private CloseFuture close () {
1721
1737
1722
1738
CloseFuture future = closeFuture .get ();
@@ -1726,9 +1742,15 @@ private CloseFuture close() {
1726
1742
logger .debug ("Shutting down" );
1727
1743
1728
1744
// stop debouncers
1729
- nodeListRefreshRequestDebouncer .stop ();
1730
- nodeRefreshRequestDebouncer .stop ();
1731
- schemaRefreshRequestDebouncer .stop ();
1745
+ if (nodeListRefreshRequestDebouncer != null ) {
1746
+ nodeListRefreshRequestDebouncer .stop ();
1747
+ }
1748
+ if (nodeRefreshRequestDebouncer != null ) {
1749
+ nodeRefreshRequestDebouncer .stop ();
1750
+ }
1751
+ if (schemaRefreshRequestDebouncer != null ) {
1752
+ schemaRefreshRequestDebouncer .stop ();
1753
+ }
1732
1754
1733
1755
// If we're shutting down, there is no point in waiting on scheduled reconnections, nor on
1734
1756
// notifications
@@ -1739,7 +1761,9 @@ private CloseFuture close() {
1739
1761
1740
1762
// but for the worker executor, we want to let submitted tasks finish unless the shutdown is
1741
1763
// forced.
1742
- executor .shutdown ();
1764
+ if (executor != null ) {
1765
+ executor .shutdown ();
1766
+ }
1743
1767
1744
1768
// We also close the metrics
1745
1769
if (metrics != null ) metrics .shutdown ();
@@ -1756,7 +1780,9 @@ private CloseFuture close() {
1756
1780
1757
1781
// Then we shutdown all connections
1758
1782
List <CloseFuture > futures = new ArrayList <CloseFuture >(sessions .size () + 1 );
1759
- futures .add (controlConnection .closeAsync ());
1783
+ if (controlConnection != null ) {
1784
+ futures .add (controlConnection .closeAsync ());
1785
+ }
1760
1786
for (Session session : sessions ) futures .add (session .closeAsync ());
1761
1787
1762
1788
future = new ClusterCloseFuture (futures );
@@ -1771,11 +1797,13 @@ private CloseFuture close() {
1771
1797
}
1772
1798
1773
1799
private void shutdownNow (ExecutorService executor ) {
1774
- List <Runnable > pendingTasks = executor .shutdownNow ();
1775
- // If some tasks were submitted to this executor but not yet commenced, make sure the
1776
- // corresponding futures complete
1777
- for (Runnable pendingTask : pendingTasks ) {
1778
- if (pendingTask instanceof FutureTask <?>) ((FutureTask <?>) pendingTask ).cancel (false );
1800
+ if (executor != null ) {
1801
+ List <Runnable > pendingTasks = executor .shutdownNow ();
1802
+ // If some tasks were submitted to this executor but not yet commenced, make sure the
1803
+ // corresponding futures complete
1804
+ for (Runnable pendingTask : pendingTasks ) {
1805
+ if (pendingTask instanceof FutureTask <?>) ((FutureTask <?>) pendingTask ).cancel (false );
1806
+ }
1779
1807
}
1780
1808
}
1781
1809
@@ -2729,17 +2757,27 @@ public void run() {
2729
2757
// user
2730
2758
// call force(), we'll never really block forever.
2731
2759
try {
2732
- reconnectionExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2733
- scheduledTasksExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2734
- executor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2735
- blockingExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2760
+ if (reconnectionExecutor != null ) {
2761
+ reconnectionExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2762
+ }
2763
+ if (scheduledTasksExecutor != null ) {
2764
+ scheduledTasksExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2765
+ }
2766
+ if (executor != null ) {
2767
+ executor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2768
+ }
2769
+ if (blockingExecutor != null ) {
2770
+ blockingExecutor .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
2771
+ }
2736
2772
2737
2773
// Some of the jobs on the executors can be doing query stuff, so close the
2738
2774
// connectionFactory at the very last
2739
- connectionFactory .shutdown ();
2740
-
2741
- reaper .shutdown ();
2742
-
2775
+ if (connectionFactory != null ) {
2776
+ connectionFactory .shutdown ();
2777
+ }
2778
+ if (reaper != null ) {
2779
+ reaper .shutdown ();
2780
+ }
2743
2781
set (null );
2744
2782
} catch (InterruptedException e ) {
2745
2783
Thread .currentThread ().interrupt ();
0 commit comments