2727import java .util .Set ;
2828import org .apache .zookeeper .KeeperException ;
2929import org .apache .zookeeper .WatchedEvent ;
30- import org .apache .zookeeper .Watcher ;
3130import org .apache .zookeeper .ZooDefs ;
31+ import org .apache .zookeeper .server .DumbWatcher ;
3232import org .apache .zookeeper .server .ServerCnxn ;
3333import org .apache .zookeeper .server .ServerCnxnFactory ;
3434import org .apache .zookeeper .server .ZooKeeperServer ;
5858 * Note: It is not expected that there would be too many distinct client URIs so as to overwhelm
5959 * heap usage.
6060 */
61- public class ZkClientUriDomainMappingHelper implements Watcher , ClientUriDomainMappingHelper {
61+ public class ZkClientUriDomainMappingHelper implements ClientUriDomainMappingHelper {
6262
6363 private static final Logger LOG = LoggerFactory .getLogger (ZkClientUriDomainMappingHelper .class );
6464
@@ -106,9 +106,13 @@ boolean setDomainAuthUpdater(ConnectionAuthInfoUpdater updater) {
106106
107107 /**
108108 * Install a persistent recursive watch on the root path.
109+ * The watcher has to be added here instead of in {@link org.apache.zookeeper.server.auth.znode.groupacl.X509ZNodeGroupAclProvider}
110+ * because this class is one layer above connections, and is a central place to handle add watch,
111+ * process event, etc logic for all the connections in this server.
112+ * Therefore, only one watch needs to be added per server.
109113 */
110114 private void addWatches () {
111- zks .getZKDatabase ().addWatch (rootPath , this , ZooDefs .AddWatchModes .persistentRecursive );
115+ zks .getZKDatabase ().addWatch (rootPath , new MappingRootWatcher () , ZooDefs .AddWatchModes .persistentRecursive );
112116 }
113117
114118 /**
@@ -141,33 +145,6 @@ private void parseZNodeMapping() {
141145 clientUriToDomainNames = newClientUriToDomainNames ;
142146 }
143147
144- @ Override
145- public void process (WatchedEvent event ) {
146- LOG .info ("Processing watched event: {}" , event .toString ());
147- parseZNodeMapping ();
148- // Update AuthInfo for all the known connections.
149- // Note : It is not ideal to iterate over all plaintext connections which are connected over non-TLS but right now
150- // there is no way to find out if connection on unified port is using SSLHandler or nonSSLHandler. Anyways, we
151- // should not ideally have any nonSSLHandler connections on unified port after complete rollout.
152-
153- // TODO Change to read SecureServerCnxnFactory only. The current logic is to support unit test who is not creating
154- // a secured server cnxn factory. It won't cause any problem but is not technically correct.
155-
156- // Since port unification is supported, TLS requests could be made on unified as well as secure port. Hence iterate
157- // over all connections to update auth info.
158- ServerCnxnFactory factory = zks .getServerCnxnFactory ();
159- LOG .info ("Updating auth info for connections" );
160- // TODO Evaluate performance impact and potentially use thread pool to parallelize the AuthInfo update.
161- if (factory != null ) {
162- factory .getConnections ().forEach (cnxn -> updateDomainBasedAuthInfo (cnxn ));
163- }
164- ServerCnxnFactory secureFactory = zks .getSecureServerCnxnFactory ();
165- LOG .info ("Updating auth info for TLS connections" );
166- if (secureFactory != null ) {
167- secureFactory .getConnections ().forEach (cnxn -> updateDomainBasedAuthInfo (cnxn ));
168- }
169- }
170-
171148 @ Override
172149 public Set <String > getDomains (String clientUri ) {
173150 return clientUriToDomainNames .getOrDefault (clientUri , Collections .emptySet ());
@@ -183,4 +160,38 @@ public void updateDomainBasedAuthInfo(ServerCnxn cnxn) {
183160 }
184161 }
185162 }
163+
164+ /**
165+ * The watcher used to listen on client uri - domain mapping root path for mapping update
166+ * Extends DumbWatcher instead of ServerCnxn because there are some package-private methods in
167+ * ServerCnxn which cannot be overridden here, such as {@code abstract void setSessionId(long sessionId);}.
168+ */
169+ public class MappingRootWatcher extends DumbWatcher {
170+ @ Override
171+ public void process (WatchedEvent event ) {
172+ LOG .info ("Processing watched event: {}" , event .toString ());
173+ parseZNodeMapping ();
174+ // Update AuthInfo for all the known connections.
175+ // Note : It is not ideal to iterate over all plaintext connections which are connected over non-TLS but right now
176+ // there is no way to find out if connection on unified port is using SSLHandler or nonSSLHandler. Anyways, we
177+ // should not ideally have any nonSSLHandler connections on unified port after complete rollout.
178+
179+ // TODO Change to read SecureServerCnxnFactory only. The current logic is to support unit test who is not creating
180+ // a secured server cnxn factory. It won't cause any problem but is not technically correct.
181+
182+ // Since port unification is supported, TLS requests could be made on unified as well as secure port. Hence iterate
183+ // over all connections to update auth info.
184+ ServerCnxnFactory factory = zks .getServerCnxnFactory ();
185+ LOG .info ("Updating auth info for connections" );
186+ // TODO Evaluate performance impact and potentially use thread pool to parallelize the AuthInfo update.
187+ if (factory != null ) {
188+ factory .getConnections ().forEach (cnxn -> updateDomainBasedAuthInfo (cnxn ));
189+ }
190+ ServerCnxnFactory secureFactory = zks .getSecureServerCnxnFactory ();
191+ LOG .info ("Updating auth info for TLS connections" );
192+ if (secureFactory != null ) {
193+ secureFactory .getConnections ().forEach (cnxn -> updateDomainBasedAuthInfo (cnxn ));
194+ }
195+ }
196+ }
186197}
0 commit comments