/src/main/com/mongodb/DynamicConnectionStatus.java

https://github.com/CengageEng/mongo-java-driver · Java · 195 lines · 147 code · 24 blank · 24 comment · 29 complexity · 58c67b730589a0d4fcff919550168150 MD5 · raw file

  1. /**
  2. * Copyright (c) 2008 - 2012 10gen, Inc. <http://10gen.com>
  3. * <p/>
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. * <p/>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p/>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.mongodb;
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import java.util.concurrent.ExecutorService;
  20. import java.util.concurrent.Executors;
  21. import java.util.concurrent.RejectedExecutionException;
  22. import java.util.logging.Level;
  23. import java.util.logging.Logger;
  24. /**
  25. * Responsible for dynamically determining whether the list of server address represents a set of mongos server or
  26. * a replica set. It starts threads that call the ismaster command on every server in the seed list, and as soon as it
  27. * reaches one determines what type of server it is. It then creates the appropriate ConnectionStatus implementation
  28. * and forwards all calls to it.
  29. */
  30. class DynamicConnectionStatus extends ConnectionStatus {
  31. private static final Logger logger = Logger.getLogger("com.mongodb.DynamicConnectionStatus");
  32. DynamicConnectionStatus(Mongo mongo, List<ServerAddress> mongosAddresses) {
  33. super(mongosAddresses, mongo);
  34. }
  35. @Override
  36. void start() {
  37. super.start();
  38. executorService = Executors.newFixedThreadPool(_mongosAddresses.size());
  39. initExecutorService();
  40. }
  41. @Override
  42. void close() {
  43. if (connectionStatus != null) {
  44. connectionStatus.close();
  45. }
  46. if (executorService != null) {
  47. executorService.shutdownNow();
  48. }
  49. super.close();
  50. }
  51. ReplicaSetStatus asReplicaSetStatus() {
  52. ConnectionStatus connectionStatus = getConnectionStatus();
  53. if (connectionStatus instanceof ReplicaSetStatus) {
  54. return (ReplicaSetStatus) connectionStatus;
  55. }
  56. return null;
  57. }
  58. MongosStatus asMongosStatus() {
  59. ConnectionStatus connectionStatus = getConnectionStatus();
  60. if (connectionStatus instanceof MongosStatus) {
  61. return (MongosStatus) connectionStatus;
  62. }
  63. return null;
  64. }
  65. @Override
  66. List<ServerAddress> getServerAddressList() {
  67. if (connectionStatus != null) {
  68. return connectionStatus.getServerAddressList();
  69. } else {
  70. return new ArrayList<ServerAddress>(_mongosAddresses);
  71. }
  72. }
  73. @Override
  74. boolean hasServerUp() {
  75. ConnectionStatus connectionStatus = getConnectionStatus();
  76. if (connectionStatus != null) {
  77. return connectionStatus.hasServerUp();
  78. } else {
  79. return false;
  80. }
  81. }
  82. @Override
  83. Node ensureMaster() {
  84. ConnectionStatus connectionStatus = getConnectionStatus();
  85. if (connectionStatus != null) {
  86. return connectionStatus.ensureMaster();
  87. } else {
  88. return null;
  89. }
  90. }
  91. void initExecutorService() {
  92. try {
  93. for (final ServerAddress cur : _mongosAddresses) {
  94. executorService.submit(new Runnable() {
  95. @Override
  96. public void run() {
  97. DynamicNode node = new DynamicNode(cur, _mongo, _mongoOptions);
  98. try {
  99. while (!Thread.interrupted()) {
  100. try {
  101. node.update();
  102. if (node._ok) {
  103. notifyOfOkNode(node);
  104. return;
  105. }
  106. } catch (Exception e) {
  107. logger.log(Level.WARNING, "couldn't reach " + node._addr, e);
  108. }
  109. int sleepTime = updaterIntervalNoMasterMS;
  110. Thread.sleep(sleepTime);
  111. }
  112. } catch (InterruptedException e) {
  113. // fall through
  114. }
  115. }
  116. });
  117. }
  118. } catch (RejectedExecutionException e) {
  119. // Ignore, as this can happen if a good node is found before all jobs are submitted and the service has
  120. // been shutdown.
  121. }
  122. }
  123. private void notifyOfOkNode(DynamicNode node) {
  124. synchronized (this) {
  125. if (connectionStatus != null) {
  126. return;
  127. }
  128. if (node.isMongos) {
  129. connectionStatus = new MongosStatus(_mongo, _mongosAddresses);
  130. } else {
  131. connectionStatus = new ReplicaSetStatus(_mongo, _mongosAddresses);
  132. }
  133. notifyAll();
  134. }
  135. connectionStatus.start();
  136. executorService.shutdownNow();
  137. }
  138. static class DynamicNode extends UpdatableNode {
  139. DynamicNode(final ServerAddress addr, Mongo mongo, MongoOptions mongoOptions) {
  140. super(addr, mongo, mongoOptions);
  141. }
  142. @Override
  143. protected Logger getLogger() {
  144. return logger;
  145. }
  146. @Override
  147. public CommandResult update() {
  148. CommandResult res = super.update();
  149. if (res != null) {
  150. String msg = res.getString("msg");
  151. if (msg != null && msg.equals("isdbgrid")) {
  152. isMongos = true;
  153. }
  154. }
  155. return res;
  156. }
  157. private boolean isMongos;
  158. }
  159. private synchronized ConnectionStatus getConnectionStatus() {
  160. if (connectionStatus == null) {
  161. try {
  162. wait(_mongoOptions.connectTimeout);
  163. } catch (InterruptedException e) {
  164. throw new MongoInterruptedException("Interrupted while waiting for next update to dynamic status", e);
  165. }
  166. }
  167. return connectionStatus;
  168. }
  169. private volatile ConnectionStatus connectionStatus;
  170. private ExecutorService executorService;
  171. }